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中的代码。