EP14 - 调整架构 EC2 与负载平衡器

昨天我们很有胆试的将 VPC 砍掉重建,
为的就是将网段重新安排,
但是还没处理好的部分,
则是 Gitlab 和 Jenkins 目前还连不上,
比较理想的方式是我们建一个 VPC Endpoint 直连 AWS,
但是尝试了很久在我本机环境建不起来,
所以这个坑只能晚点填,
建议有点规模的公司,
可以考虑建立一个 Site-to-Site VPN,
当作内网的延伸,
这样 172.31 某个网段以後的都是 aws,
以前的是地端主机,
这样会更好分辨与管理。

我们没有要建 VPN,
可是我们还是有连到 Jenkins 和 Gitlab 的需求,
这时候我们可以考虑之前做的 ALB(Application Load Balance),
前几天我们帮 Portal 建立的 ALB,
其 ALB 和 EC2 套用的 Security Group 是一样的,
都是收 22、80、443 port,
但是 ALB 只能监听 80 和 443,
所以即使开了 22 port,
还是只能透过我们绑定的 Elastic IP 去管理主机,
而 ALB 又可以挂载 Web ACLs,
所以整体的安全有保护到,
今天我们 Gitlab 和 Jenkins 也打算使用差不多的方式,
我们建立新的 Security Group,
但是只绑定 Stage VPC 的 CIDR 和我们私人的 IP,
这样在设定完 DNS 後,
在 Load Balance 就可以根据 IP 白名单来过去,
不在 CIDR 中的就不允许进入。


建立 ALB

建立的部分虽然都在 stage/main.tf
但是我们分四个区块

  1. 建立 Security Group
  2. ALB For Jenkins
  3. ALB For Gitlab
  4. ALB 绑定 WebACLs

这里我们不使用 NLB
系因为 NLB 无法设定 Security Group
也无法绑定 Web ACLs
无法绑定 Web ACLs 问题不大
但是无法锁定特定 IP 才能存取
就会变成 CI/CD Tools 在网路上裸奔
这不会是我们热见的
大部分我们的操作都会是连进去点按
比较少会 ssh 进去上 patch
因此这部分我是觉得可以暂时使用 ALB
如果真的需要其实可以偷鸡一点
将 pem key scp 到 portal 或是跳板用的主机
等操作完再把 pem key 删除

建立 Security Group

一开始我们设定的
stage/main.tf

resource "aws_security_group" "elb_internal" {
    name        = "elb-internal"
    description = "It used for load balance internal."
    vpc_id      = aws_vpc.stage.id
    tags        = { Name = "elb-internal" }
    revoke_rules_on_delete = null
}

resource "aws_security_group_rule" "elb_internal_igress_80" {
    type              = "ingress"
    from_port         = 80
    to_port           = 80
    cidr_blocks       = [aws_vpc.stage.cidr_block, var.personal_cidr]
    protocol          = "tcp"
    security_group_id = aws_security_group.elb_internal.id
}

resource "aws_security_group_rule" "elb_internal_igress_443" {
    type              = "ingress"
    from_port         = 443
    to_port           = 443
    cidr_blocks       = [aws_vpc.stage.cidr_block, var.personal_cidr]
    protocol          = "tcp"
    security_group_id = aws_security_group.elb_internal.id
}

resource "aws_security_group_rule" "elb_internal_egress" {
    type              = "egress"
    from_port         = 0
    to_port           = 0
    cidr_blocks       = ["0.0.0.0/0",]
    protocol          = "-1"
    security_group_id = aws_security_group.elb_internal.id
}

Jenkins

portal 的部分,
target group 是使用 IP 的写法,
这次我们换换味道,
换成 instance 的写法。

stage/main.tf

resource "aws_lb" "jenkins" {
    name               = "jenkins"
    internal           = false
    load_balancer_type = "application"
    security_groups    = [ aws_security_group.elb_internal.id ]
    subnets            = data.aws_subnet_ids.public_subnet_ids.ids
    
    enable_deletion_protection = false
    
    tags = {
        Creator = "Terraform"
    }
}

resource "aws_lb_target_group" "jenkins_tcp_8080" {
    name        = "jenkins"
    port        = 80
    protocol    = "HTTP"
    target_type = "instance"
    vpc_id      = aws_vpc.stage.id
}

resource "aws_lb_target_group_attachment" "jenkins_tcp_8080" {
    target_group_arn = aws_lb_target_group.jenkins_tcp_8080.arn
    target_id        = module.ec2_jenkins.id
    port             = 8080
}

resource "aws_lb_listener" "jenkins_tcp_80" {
    load_balancer_arn = aws_lb.jenkins.arn
    port = "80"
    protocol = "HTTP"

    default_action {
        type             = "redirect"
        target_group_arn = aws_lb_target_group.jenkins_tcp_8080.arn
        
        redirect {
            port        = "443"
            protocol    = "HTTPS"
            status_code = "HTTP_301"
        }
    }
}

resource "aws_lb_listener" "jenkins_tcp_443" {
    load_balancer_arn = aws_lb.jenkins.arn
    port              = "443"
    protocol          = "HTTPS"
    ssl_policy        = "ELBSecurityPolicy-2016-08"
    certificate_arn   = aws_acm_certificate.cert.arn
    
    default_action {
        type             = "forward"
        target_group_arn = aws_lb_target_group.jenkins_tcp_8080.arn
    }
}

Gitlab

portal 的部分,
target group 是使用 IP 的写法,
这次我们和 Gitlab 一样换换味道,
换成 instance 的写法。

resource "aws_lb_target_group" "gitlab" {
    name        = "gitlab"
    port        = 80
    protocol    = "HTTP"
    target_type = "instance"
    vpc_id      = aws_vpc.stage.id
}

resource "aws_lb_target_group_attachment" "gitlab" {
    target_group_arn = aws_lb_target_group.gitlab.arn
    target_id        = module.ec2_gitlab.id
    port             = 80
}

resource "aws_lb_listener" "gitlab_80" {
    load_balancer_arn = aws_lb.gitlab.arn
    port = "80"
    protocol = "HTTP"

    default_action {
        type             = "redirect"
        target_group_arn = aws_lb_target_group.gitlab.arn
        
        redirect {
            port        = "443"
            protocol    = "HTTPS"
            status_code = "HTTP_301"
        }
    }
}

resource "aws_lb_listener" "gitlab_443" {
    load_balancer_arn = aws_lb.gitlab.arn
    port              = "443"
    protocol          = "HTTPS"
    ssl_policy        = "ELBSecurityPolicy-2016-08"
    certificate_arn   = aws_acm_certificate.cert.arn
    
    default_action {
        type             = "forward"
        target_group_arn = aws_lb_target_group.gitlab.arn
    }
}

WebACLs

stage/main.tf

resource "aws_wafv2_web_acl_association" "jenkins" {
    resource_arn = aws_lb.jenkins.arn
    web_acl_arn  = aws_wafv2_web_acl.fundamental_acl.arn
}

执行配置

terraform apply

DNS 指向

检视 ALB 的 DNS

执行完配置以後
我们登入 AWS Cloud Console
可在 EC2 的负载平衡器看到我们刚刚建立的 ALB

https://ithelp.ithome.com.tw/upload/images/20210926/20141518oHMpRL4pVb.png

设定 DNS 指向

接下来就是要去自己的 DNS Server 设定 CNAME Record

https://ithelp.ithome.com.tw/upload/images/20210926/20141518uzdkoTt0oO.png

https://ithelp.ithome.com.tw/upload/images/20210926/20141518ncTz7IGGdR.png

虽然刚刚我有试着遮 Load Balance 的 DNS Host
不过实际上懂技术的人
还是可以知道 DNS Host 和 IP 是什麽
不过即使知道
也会因为 Security Group 挡住而连不上

调整 CI/CD 设定

调整 Jenkins 设定

管理 Jenkins

登入後点按左侧选的「管理 Jenkins」
https://ithelp.ithome.com.tw/upload/images/20210926/20141518F2F56TSX9J.png

设定 Jnekins

https://ithelp.ithome.com.tw/upload/images/20210926/20141518blfG21iJZv.png

修改 Jenkins 位置

画面中间的「Jenkins URL」改成自己的网址
https://ithelp.ithome.com.tw/upload/images/20210926/20141518PL2y7wOF6Z.png

修改 Jenkinsfile

之前的教学中
我们的 Jenkinsfile 还没进版控
这时候我们可以从 Pipeline 进去修改

点按组态

在 Pipeline 的向下箭头点按後选择「组态」
https://ithelp.ithome.com.tw/upload/images/20210926/201415186JSa3zAKy9.png

编辑 Gitlab URL

将 Git Repository 的内网 IP 贴上,并储存
https://ithelp.ithome.com.tw/upload/images/20210926/20141518cKWjuFC215.png

修改 Gitlab 设定

将 gitlab 的 pem key 上传到 portal

sudo scp -i "/vagrant_data/project/terraform/stage/portal.pem" "/vagrant_data/project/terraform/stage/gitlab.pem" [email protected]:/home/ubuntu

调整 portal port 22 inbound/outbound

当时我们对 portal 只有设定本机电脑
为了要使用 portal 当跳板到 Gitlab 改设定
因此我们需要将 port 22 的 inbound/outbound 做修改
改成 vpc 内的 ip 都可以连

resource "aws_security_group_rule" "ithome_ironman_igress_22" {
    type              = "ingress"
    from_port         = 22
    to_port           = 22
    cidr_blocks       = [var.personal_cidr, aws_vpc.stage.cidr_block]
    protocol          = "tcp"
    security_group_id = aws_security_group.ithome_ironman_portal.id
}

resource "aws_security_group_rule" "ithome_ironman_egress_22" {
    type              = "egress"
    from_port         = 22
    to_port           = 22
    cidr_blocks       = [var.personal_cidr, aws_vpc.stage.cidr_block]
    protocol          = "tcp"
    security_group_id = aws_security_group.ithome_ironman_portal.id
}

ssh 到 portal

ssh -i "/vagrant_data/project/terraform/stage/portal.pem" ubuntu@portal的EIP

修改 pem key 权限

sudo chmod 400 gitlab.pem

编辑 gitlab 组态

sudo vi /etc/gitlab/gitlab.rb 

将 external url 改成 gitlab 网址

https://ithelp.ithome.com.tw/upload/images/20210926/20141518mPNVTDApEG.png

重新组态

sudo gitlab-ctl reconfigure

在 gitlab-ctl reconfigure 过程中有出错是正常的
因为我们 Load Balance 只有锁内网和个人 IP
因此 let's encryption 在产生凭证的时候就会无法验证而出错
在意这问题的人
其实可以先把 security 打开,验证好之後再关闭
这样做我们就会得到奇怪的架构
一个是 aws 的自发凭证
另一个则是 load balance 到 EC2 的 Let's Encryption 凭证

重新启动 Gitlab

sudo gitlab-ctl restart

离开 Gitlab

exit

删除 portal 上的 pem key

sudo rm -rf gitlab.pem

离开 portal

exit

将 gitlab_80 和 gitlab 443 注解

因为我们要修改 target group
因此要先将正在监听中的 80 和 443 port 注解(删除)

# resource "aws_lb_listener" "gitlab_80" {
#     load_balancer_arn = aws_lb.gitlab.arn
#     port = "80"
#     protocol = "HTTP"

#     default_action {
#         type             = "redirect"
#         target_group_arn = aws_lb_target_group.gitlab.arn
        
#         redirect {
#             port        = "443"
#             protocol    = "HTTPS"
#             status_code = "HTTP_301"
#         }
#     }
# }

# resource "aws_lb_listener" "gitlab_443" {
#     load_balancer_arn = aws_lb.gitlab.arn
#     port              = "443"
#     protocol          = "HTTPS"
#     ssl_policy        = "ELBSecurityPolicy-2016-08"
#     certificate_arn   = aws_acm_certificate.cert.arn
    
#     default_action {
#         type             = "forward"
#         target_group_arn = aws_lb_target_group.gitlab.arn
#     }
# }

修改 target group

原本是 80 port 改成 443 port

resource "aws_lb_target_group" "gitlab" {
    name        = "gitlab"
    port        = 443
    protocol    = "HTTPS"
    target_type = "instance"
    vpc_id      = aws_vpc.stage.id
}

resource "aws_lb_target_group_attachment" "gitlab" {
    target_group_arn = aws_lb_target_group.gitlab.arn
    target_id        = module.ec2_gitlab.id
    port             = 443
}

执行配置

terraform apply

将 gitlab_80 和 gitlab 443 取消注解

这边需要先注解掉再取消注解
是因为没有这样做
会造成 Target Group 有绑定监听
因此一直无法删除重建

resource "aws_lb_listener" "gitlab_80" {
    load_balancer_arn = aws_lb.gitlab.arn
    port = "80"
    protocol = "HTTP"

    default_action {
        type             = "redirect"
        target_group_arn = aws_lb_target_group.gitlab.arn
        
        redirect {
            port        = "443"
            protocol    = "HTTPS"
            status_code = "HTTP_301"
        }
    }
}

resource "aws_lb_listener" "gitlab_443" {
    load_balancer_arn = aws_lb.gitlab.arn
    port              = "443"
    protocol          = "HTTPS"
    ssl_policy        = "ELBSecurityPolicy-2016-08"
    certificate_arn   = aws_acm_certificate.cert.arn
    
    default_action {
        type             = "forward"
        target_group_arn = aws_lb_target_group.gitlab.arn
    }
}

进入 admin 介面修改设定

因为我们之後要改走内网
所以需要开启 local network 的设定
Admin -> Settings -> Network -> Outbound Requests -> Allow requests to the local network from hooks and services
勾选 Allow requests to the local network from hooks and services
https://ithelp.ithome.com.tw/upload/images/20210926/20141518lBaOo7Jj6y.png

修改专案的 Webhook 设定

将 Webhook 的 Jenkins URL 改成内网 IP 的 URL
https://ithelp.ithome.com.tw/upload/images/20210926/20141518FWHe1LtSok.png

修改本机 Repository

因为我们使用 alb 以後
只剩下 80 和 443 port
因此只能走 https 来 clone repository

毕竟帐号密码也算是机密资讯
Gitlab 有提供一个不错的功能
让我们来建立 Token
使用 Token 的方式来存取

有些环境下会限制 ssh 的存取
这时候走 https 的话
使用 token 的方式来存取是相对安全的做法

建立 Token

在专案中的 Settings,可选取 Access_Token 建立 Token
https://ithelp.ithome.com.tw/upload/images/20210926/20141518jDqpRgsqWZ.png

更改 repositroy

git remote set-url origin https://使用者名称:[email protected]/ithome-ironman-2021/portal.git

尝试抓取远端

git fetch origin

CodeDeploy 如果莫名失败的,请参考这篇,需要建立一个新的 IAM Role,然後原本 EC2 绑定的解绑,绑定新的没权限的,再解绑然後绑定回原来的。


大方向来说,
架构调整会先在这里告一段落,
这里先说声抱歉,
能力上的不足,
本来想把 VPN 环境建置起来,
这样就可以顺利连到 VPC 直接顺取内网资源。

或是在 Route53 中建立自订托管区域,
这样会因为 DHCP 的设定,
而解析到 host,
让我们服务在内部沟通时,
可以不用绑 EC2 或是 IP 绑很死,
但是无奈遇到一些技术上的问题就暂时作罢。

明天我会中场休息做个闲聊,
接下来我们的步骤会有些不同,
继续进行改造,

将我们的服务打包成 Docker,
并使用 AWS 的 Kubernetes 服务(EKS)管理,
接着搭配新的部署工具 Octopus Deploy
部署到 EKS 上。

  1. CentOS7下GitLab修改域名host
  2. gitlab Import url is blocked: "Requests to the local network are not allowed"
  3. InstanceAgent::Plugins::CodeDeployPlugin::CommandPoller: Missing credentials
  4. How to Set Up Time Synchronization with NTP on Ubuntu 18.04
  5. Load Balancer for multi-node GitLab

<<:  卡夫卡的藏书阁【Book12】- KafkaJS 安装

>>:  Day11. UX/UI 设计流程之一: Functional Map (以 Axure RP 实作)

Powershell 入门之命令的输出

在命令的执行过程中,我们可能需要需要一些方式,使我们命令的输出更加友好;去除一些没有用的信息,只显示...

Day27

虽然有向下转型但透过指标呼叫方法时到底会呼叫到父类别的方法还是子类别的方法呢?来讲一个很容易弄错的地...

RDS Deadlock

有Transaction就有可能会发生Deadlock. 在RDS上发生的时候就可从LOG里看出发生...

从零开始学游戏设计:游戏音效

这是 Roblox 从零开始系列,游戏环境章节的第五个单元,今天要来教你如何在游戏中的角色作出动作之...

Day 9探讨Scanner(Ⅰ)

Scanner Objects:使用於如果要让使用者输入值的时候,就需要用到这个语法! 我将使用Da...