我使用 GitHub Actions,在 AWS + Terraform + Ansible 中搭建了一个 CI/CD 环境

总的来说

最近因为喜欢玩github actions,我在aws环境下尝试了使用teraform + ansible进行部署。
我成功搭建了EC2实例,并安装了httpd。

目录

・预先准备
・目录结构
・创建存储桶
・创建IAM用户
・创建Terraform代码
・创建Ansible代码
・创建GitHub Actions
・执行GitHub Actions并获取结果

事前准备

    EC2のIPの自動取得にdyanamic inventoryが使用できること

目录结构

├── README.md
├── ansible
│   ├── ansible.cfg
│   ├── ec2.ini
│   ├── ec2.py
│   ├── roles
│   │   ├── common
│   │   │   ├── files
│   │   │   │   └── main.yml
│   │   │   └── tasks
│   │   └── nginx
│   │       ├── files
│   │       └── tasks
│   │           └── main.yml
│   ├── sandbox.yml
└── terraform
    ├── backend.tf
    ├── data.tf
    ├── main.tf
    ├── output
    ├── output.tf
    ├── provider.tf
    └── variables.tf

创建 S3 存储桶

创建一个用于保存tfstate的存储桶。

% aws s3 mb s3://tf-sandbox-masa3521
make_bucket: tf-sandbox-masa3521

创建IAM用户

创建用于运行 Terraform 和 Ansible 的 IAM 用户。
由于需要从参数存储(Parameter Store)中获取 EC2、S3 和密钥相关信息,因此需要授予相应的权限。

% aws iam create-user --user-name cicd_user

{
    "User": {
        "Path": "/",
        "UserName": "cicd_user",
        "UserId": "***************",
        "Arn": "arn:aws:iam::***************:user/cicd_user",
        "CreateDate": "2020-05-21T15:05:18Z"
    }
}
% aws iam create-access-key --user-name cicd_user
{
    "AccessKey": {
        "UserName": "cicd_user",
        "AccessKeyId": "***************",
        "Status": "Active",
        "SecretAccessKey": "***************",
        "CreateDate": "2020-05-22T00:42:37Z"
    }
}
% aws iam attach-user-policy --policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess  --user-name cicd_user
% aws iam attach-user-policy --policy-arn arn:aws:iam::aws:policy/AmazonEC2FullAccess --user-name cicd_user
% aws iam attach-user-policy --policy-arn arn:aws:iam::aws:policy/AmazonSSMReadOnlyAccess --user-name cicd_user
% aws iam list-attached-user-policies --user-name cicd_user
{
    "AttachedPolicies": [
        {
            "PolicyName": "AmazonEC2FullAccess",
            "PolicyArn": "arn:aws:iam::aws:policy/AmazonEC2FullAccess"
        },
        {
            "PolicyName": "AmazonS3FullAccess",
            "PolicyArn": "arn:aws:iam::aws:policy/AmazonS3FullAccess"
        },
        {
            "PolicyName": "AmazonSSMReadOnlyAccess",
            "PolicyArn": "arn:aws:iam::aws:policy/AmazonSSMReadOnlyAccess"
        }
    ]
}

制作密钥

创建适用于 EC2 的公钥/私钥并将其注册到参数存储。

% ssh-keygen -t rsa -b 4096  
% aws ssm put-parameter --name "publickey" \
                      --type SecureString \
                      --value  "$(cat id_rsa.pub)"

{
    "Version": 1,
    "Tier": "Standard"
}

% aws ssm put-parameter --name "pravatekey" \
                      --type SecureString \
                      --value  "$(cat id_rsa)"

{
    "Version": 1,
    "Tier": "Standard"
}

创建Terraform代码

    • data.tfで公開鍵をパラメータストアから取得

 

    • backend.tfでtfstateをリモートで管理

 

    output.tfでセキュリティーグループのgroupidをファイルに出力 ※後のgithub-actionsで使用
provider "aws" {
  profile = "default"
  version = "= 2.61"
  region  = "ap-northeast-1"
}
terraform {
  backend "s3" {
    bucket  = "tf-sandbox-masa3521"
    region  = "ap-northeast-1"
    key     = "terraform.tfstate"
    encrypt = true
  }
}
data "aws_ssm_parameter" "publickey" {
  name            = "publickey"
  with_decryption = true
}
variable "region" {
  default = "ap-northeast-1"
}

variable "system" {
  default = "sandbox"
}
resource "local_file" "sgroupid" {
  filename = "./group_id"
  content  = aws_security_group.sandboxSG.id
}

resource "aws_vpc" "sandboxVPC" {
  cidr_block           = "10.1.0.0/16"
  instance_tenancy     = "default"
  enable_dns_support   = "true"
  enable_dns_hostnames = "false"
  tags = {
    Name = var.system
    Env  = terraform.workspace
  }
}

resource "aws_route_table" "sanbboxRT" {
  vpc_id = aws_vpc.sandboxVPC.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.sandboxGW.id
  }

  tags = {
    Name = var.system
    Env  = terraform.workspace
  }
}

resource "aws_subnet" "sandboxSUBNET" {
  vpc_id     = aws_vpc.sandboxVPC.id
  cidr_block = "10.1.0.0/24"
  tags = {
    Name = var.system
    Env  = terraform.workspace
  }
}

resource "aws_internet_gateway" "sandboxGW" {
  vpc_id = aws_vpc.sandboxVPC.id
  tags = {
    Name = var.system
    Env  = terraform.workspace
  }
}

resource "aws_route_table_association" "sandboxRTA" {
  subnet_id      = aws_subnet.sandboxSUBNET.id
  route_table_id = aws_route_table.sanbboxRT.id
}

resource "aws_security_group" "sandboxSG" {
  name        = "sandboxSG"
  description = "Allow SSH inbound traffic"
  vpc_id      = aws_vpc.sandboxVPC.id
  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
  tags = {
    Name = var.system
    Env  = terraform.workspace
  }
}

resource "aws_key_pair" "publickey" {
  key_name   = "key"
  public_key = data.aws_ssm_parameter.publickey.value
  tags = {
    Name = var.system
    Env  = terraform.workspace
  }
}

resource "aws_instance" "sandboxinstance" {
  key_name      = aws_key_pair.publickey.id
  ami           = "ami-0f310fced6141e627"
  instance_type = "t2.nano"
  vpc_security_group_ids = [
    aws_security_group.sandboxSG.id
  ]

  subnet_id                   = aws_subnet.sandboxSUBNET.id
  associate_public_ip_address = "true"
  tags = {
    Name = var.system
    Env  = terraform.workspace
  }
}

用ansible创建

[defaults]
deprecation_warnings = False
remote_user = ec2-user
private_key_file = ./privatekey
host_key_checking = False
- hosts: tag_Name_sandbox
  roles:
    - htted
---
- name: install apache
  yum:
   name: httpd
   state: present
  become: true
- name: Start httpd
  service:
    name: httpd
    state: started
    enabled: yes
  become: true

创建github-actions

    • 実行の為にsecretsの登録が必要

 

    • IPを自動で取得するためDynamic Inventoryで取得する。

 

    • ansble実行の為秘密鍵のダウンロード

 

    ansible実行前にセキュリティーグループに自分のIPを登録、実行後に自分のIPを削除

秘密注册

スクリーンショット 2020-05-29 1.59.30.png

name: Terraform deploy to Azure

on:
  push:
    branches:    
      - master

jobs:
  terraform-ansible:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2

    - name: Configure AWS Credentials
      uses: aws-actions/configure-aws-credentials@v1
      with:
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
        aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        aws-region: ap-northeast-1

    - name: Setup Terraform
      uses: hashicorp/setup-terraform@v1
      with:
        terraform_version: 0.12.9

    - name: Terraform Init
      run: terraform init
      working-directory: ${{ github.workspace }}/terraform

    - name: Terraform select
      run: terraform workspace select dev
      working-directory: ${{ github.workspace }}/terraform

    - name: Terraform Format
      run: terraform fmt -check
      working-directory: ${{ github.workspace }}/terraform

    - name: Terraform Plan
      run: terraform plan
      working-directory: ${{ github.workspace }}/terraform

    - name: Terraform Apply
      if: github.ref == 'refs/heads/master' && github.event_name == 'push'
      run: terraform apply -auto-approve
      working-directory: ${{ github.workspace }}/terraform

    - name: Set up Python 3.7
      uses: actions/setup-python@v2
      with:
        python-version: 3.7

    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install boto ansible==2.9.2

    - name: Download privatekey
      run: aws ssm get-parameter --name "privatekey" --with-decryption | jq -r .Parameter.Value > ./privatekey
      working-directory: ${{ github.workspace }}/ansible

    - name: modify permission privatekey
      run: chmod 400 ./privatekey
      working-directory: ${{ github.workspace }}/ansible

    - name: open sg
      run:  aws ec2 authorize-security-group-ingress --group-id "$(cat ../terraform/group_id)" --protocol tcp --port 22 --cidr `curl inet-ip.info`/32
      working-directory: ${{ github.workspace }}/ansible

    - name: exec ansible
      run: ansible-playbook -i ec2.py sandbox.yml
      working-directory: ${{ github.workspace }}/ansible

    - name: close sg
      run:  aws ec2 revoke-security-group-ingress --group-id "$(cat ../terraform/group_id)" --protocol tcp --port 22 --cidr `curl inet-ip.info`/32
      working-directory: ${{ github.workspace }}/ansible

GitHub Actions 的结果

スクリーンショット 2020-05-29 2.07.50.png

【参考】
– Terraform 的 GitHub Actions 设置:https://www.terraform.io/docs/github-actions/setup-terraform.html
– 配置 AWS 凭证的 GitHub 操作:https://github.com/aws-actions/configure-aws-credentials
– Ansible 的动态清单介绍:https://docs.ansible.com/ansible/latest/user_guide/intro_dynamic_inventory.html

bannerAds