Launch a server for building Docker images using Terraform

2020年03月26日


从今天开始,我会开始从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中的代码。



Category: orchestration Tags: public

Upvote


Downvote