Launch a server for building Docker images using Terraform
从今天开始,我会开始从0到1制作一个高度自动化的持续发布流水线。
当前的环境使用AWS Global的环境和账号。已经使用了CloudFormation部署了很多功能组件。
本文开始的前提,是VPC、其中的若干子网、安全组等。这些组件的设计和创建这里不过多赘述,因为实在是太简单了。如有需要,今后会新开一篇文章进行讲述。
这里,首先我们创建一台server用来作为中央控制节点,并在其之上安装Terraform等工具。
利用Terraform,我们创建一台EC2。这个EC2在后面会用来构建Docker的镜像。
在AWS SSM中,创建一个parameter,其类型为SecureString,用来指定这里创建的本地用户所使用的密码。作为示例,这里将参数的名称命名为"docker"。它的值将被用来作为本地用户"dockerbuilder"的密码。EC2需要通过VPC内网与SSM进行通信,因此SSM的security group需要对来自Terraform控制节点所在子网的、去往SSM VPN endpoint的TCP 443端口的流量放行。
[ec2-user@ ~]$ aws ssm put-parameter --name docker1 --type SecureString --value test
创建IAM policy
read -r -d '' POLICY_DOC <<EOF { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "ecr:GetAuthorizationToken", "ecr:DescribeRepositories", "ecr:UploadLayerPart", "ecr:InitiateLayerUpload", "ssm:GetParameter", "ecr:BatchCheckLayerAvailability", "ecr:PutImage", "ecr:CompleteLayerUpload" ], "Resource": "*" } ] } EOF
[ec2-user@ ~]$ read -r -d '' POLICY_DOC <<EOF
...
> EOF
[ec2-user@ ~]$ echo "${POLICY_DOC}" > policy.json
[ec2-user@ ~]$ read -r -d '' TRUST_RELATIONSHIP <<EOF
> {
> "Version": "2012-10-17",
> "Statement": [
> {
> "Effect": "Allow",
> "Principal": {
> "Service": "ec2.amazonaws.com"
> },
> "Action": "sts:AssumeRole"
> }
> ]
> }
> EOF
[ec2-user@ ~]$ echo "${TRUST_RELATIONSHIP}" > trust.json
[ec2-user@ ~]$ PolicyArn=$(aws iam create-policy --policy-name policy-dockerserver --policy-document file://policy.json --query "Policy.Arn" --output text)
[ec2-user@ ~]$ aws iam create-role --role-name ec2role-dockerserver --assume-role-policy-document file://trust.json
[ec2-user@ ~]$ aws iam attach-role-policy --role-name ec2role-dockerserver --policy-arn=$PolicyArn
安装Terraform工具。
[ec2-user@ ~]$ curl -O https://releases.hashicorp.com/terraform/0.12.24/terraform_0.12.24_linux_amd64.zip
[ec2-user@ ~]$ sudo unzip terraform_0.12.24_linux_amd64.zip -d /usr/local/bin
[ec2-user@ ~]$ mkdir AWS && cd AWS/
[ec2-user@ AWS]$ mkdir -p {networking,compute,storage}
[ec2-user@ AWS]$ touch {networking,compute,storage}/{main.tf,variables.tf,outputs.tf}
[ec2-user@ AWS]$ touch compute/userdata.tpl
[ec2-user@ AWS]$ touch {main.tf,variables.tf,outputs.tf}
[ec2-user@ AWS]$ vim main.tf
provider "aws" { region = "${var.aws_region}" } # Deploy Compute Resources module "compute" { source = "./compute" instance_count = "${var.instance_count}" key_name = "${var.key_name}" instance_type = "${var.server_instance_type}" subnet_id = "${var.subnet_id}" iam_instance_profile = "${var.iam_instance_profile}" vpc_security_group_ids = "${var.vpc_security_group_ids}" }
[ec2-user@ AWS]$ vim variables.tf
variable "aws_region" {} variable "key_name" {} variable "server_instance_type" {} variable "instance_count" { default = 1 } variable "subnet_id" {} variable "iam_instance_profile" {} variable "vpc_security_group_ids" { type = "list" }
[ec2-user@ AWS]$ vim terraform.tfvars
aws_region = "us-west-2" project_name = "la-terrafrom" key_name = "vpn-client-aws" server_instance_type = "t3a.small" instance_count = 1 subnet_id = "subnet-###1" iam_instance_profile = "#iamrolename" vpc_security_group_ids = [ "sg-###a","sg-###b" ]
[ec2-user@ AWS]$ vim variables.tf
variable "aws_region" {} variable "project_name" {} variable "key_name" {} variable "server_instance_type" {} variable "instance_count" { default = 1 }
[ec2-user@ AWS]$ cd compute/main.tf
#---compute/main.tf data "aws_ami" "server_ami" { most_recent = true owners = ["679593333241"] filter { name = "owner-alias" values = ["aws-marketplace"] } filter { name = "virtualization-type" values = ["hvm"] } filter { name = "root-device-type" values = ["ebs"] } filter { name = "name" values = ["CentOS Linux 7 x86_64 HVM EBS ENA *"] } } data "template_file" "user-init" { template = "${file("${path.module}/userdata.tpl")}" } resource "aws_instance" "tf_server" { count = "${var.instance_count}" instance_type = "${var.instance_type}" ami = "${data.aws_ami.server_ami.id}" key_name = "${var.key_name}" vpc_security_group_ids = "${var.vpc_security_group_ids}" subnet_id = "${var.subnet_id}" user_data = "${data.template_file.user-init.rendered}" iam_instance_profile = "${var.iam_instance_profile}" root_block_device { delete_on_termination = true } tags = { Name = "DockerBuilder" } }
[ec2-user@ compute]$ vim variables.tf
variable "aws_region" {} variable "key_name" {} variable "server_instance_type" {} variable "instance_count" { default = 1 } variable "subnet_id" {} variable "iam_instance_profile" {} variable "vpc_security_group_ids" { type = "list" }
[ec2-user@ compute]$ vim userdata.tpl
#!/bin/bash sed -i '/PasswordAuthentication no/ c\PasswordAuthentication yes' /etc/ssh/sshd_config systemctl restart sshd yum install -y https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_amd64/amazon-ssm-agent.rpm yum install -y unzip dnf dnf install -y 'dnf-command(config-manager)' # Install GitHub CLI dnf config-manager --add-repo https://cli.github.com/packages/rpm/gh-cli.repo dnf install -y gh #curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py #python get-pip.py #pip install awscli --upgrade # Currently CentOS 7 does not include AWS CLI v2. Install AWS CLI v2. curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" unzip awscliv2.zip sudo ./aws/install useradd d*** aws ssm get-parameter --region us-west-2 --name "d***" --with-decryption --query "Parameter.Value" --output text | passwd d*** --stdin echo "d*** ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/d*** ssh-keygen -t rsa -b 4096 -C "l***u@hotmail.com" -f /root/.ssh/id_rsa -N "" gh auth login --with-token <<< "ghp_F****g" gh ssh-key add ~/.ssh/id_rsa.pub --title "temporary Docker server" ssh -T git@github.com -o StrictHostKeyChecking=no这里首先将SSH设置为允许密码验证,因为后面要使用Ansible通过SSH协议下发配置。
执行完这个操作后,需要重启sshd服务以使配置生效。
接下来,安装SSM agent,用来和SSM服务进行通信。
pip通常不随CentOS的AMI镜像出厂自带,需要手动安装,从而使用pip安装最新版的AWS CLI工具。
最后,通过get-parameter命令获取用户的密码,并设定为用户"dockerbuilder"的密码。
[ec2-user@ compute]$ terraform init
[ec2-user@ compute]$ terraform plan
[ec2-user@ compute]$ terraform apply
SSH到Docker server。
% ssh d123@<1.2.3.4>
d123@<1.2.3.4>'s password:
login as: d*** d123@###'s password: Last failed login: Thu Mar 26 15:16:45 UTC 2020 from 47.75.11.79 on ssh:notty-----
[ec2-user@ compute]$ terraform destroy
创建SSH并上传至GitHub,以在后面的步骤中可以有权限拉取private repository中的代码。