Try   HackMD

AWS CI/CD sample

Sample project

ディレクトリ構造

(aws-cicd-sample) takumi:~/environment/aws-cicd-sample (master) $ tree . ├── README.md ├── main │   ├── __init__.py │   ├── deleteImageById │   │   ├── __init__.py │   │   ├── delete_image_by_id.py │   │   └── requirements.txt │   ├── getImageById │   │   ├── __init__.py │   │   ├── get_image_by_id.py │   │   └── requirements.txt │   ├── getImages │   │   ├── __init__.py │   │   ├── get_images.py │   │   └── requirements.txt │   ├── postImages │   │   ├── __init__.py │   │   ├── post_images.py │   │   └── requirements.txt │   └── updateImage │   ├── __init__.py │   ├── requirements.txt │   └── update_image.py └── tests │ ├── __init__.py │ ├── postImages │    ├── __init__.py │    └── test_postImages.py ├── api-tests ├── buildspec.yml ├── samconfig.toml ├── swagger.yaml ├── template.yaml ├── sonar-scanner-4.2.0.1873-linux ├── sonar-project.properties ├── coverage.xml ├── .aws-sam    └── build    ├── template.yaml    ├── deleteImageById    │   ├── delete_image_by_id.py    │   ├── __init__.py    │   └── requirements.txt    ├── getImageById    │   ├── get_image_by_id.py    │   ├── __init__.py    │   └── requirements.txt    ├── getImages    │   ├── get_images.py    │   ├── __init__.py    │   └── requirements.txt    ├── postImages    │   ├── __init__.py    │   ├── post_images.py    │   └── requirements.txt └── updateImage    ├── __init__.py    ├── requirements.txt    └── update_image.py

Buildステップ(試行錯誤中)

手動

  1. 準備
$ pip install --upgrade aws-sam-cli
$ pip install pytest
$ pip install pytest-cov
$ wget -O tmp https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-4.2.0.1873-linux.zip
$ $unzip tmp
  1. 単体テスト
$ TABLE_NAME=photos pytest --cov=main --cov-report=xml tests/
  • ローカルで実行する場合は、pipでpytestとpytest-covを事前にインストールしておく。
  • テスト対象のモジュールがDynamoDB名を環境変数(TABLE_NAME)として利用するので、pytestコマンドの前に設定。ローカルテストとCIサーバ上テスト切分け設定を外出しにしたい(TBD)。
  1. (option)単体テスト結果をSonarQubeサーバへ転送
$ sonar-scanner-4.2.0.1873-linux/bin/sonar-scanner -Dsonar.host.url=http://ec2-18-180-2-56.ap-northeast-1.compute.amazonaws.com:22222
  • sonar-scannerはlinux用をzipでDLしたものを利用。
  • docker版もあるので、それを使うのがベターだが、CIサーバ(CodeBuild)のジョブは、dockerコンテナなので、その中でdockerコマンドが使えるか不明(dind)。ローカルなら、docker版成功。→こちら参考
  1. パッケージ(前準備)
$ sam buil
  • projectディレクトリ直下にあるtemplate.yaml(line:35)をベースに、sam-cli用のプロジェクトを生成。.aws-samディレクトリ配下が作成される(lines:39-61)。
  1. パッケージ
$ sam package --template-file template.yaml --s3-bucket aws-cicd-sample-managed-s3-bucket-artifacts --output-template-file transformed.yaml
  • projectディレクトリ直下にあるtemplate.yaml(line:35)をベースに、sam-cli用のプロジェクトを生成。.aws-samディレクトリ配下が作成される(lines:39-61)。
    - デプロイ用のtransformed.yaml(template.yamlに実際のリソースID(ARNとか)が定義されたもの)はプロジェクト直下に作成されるようだ。
  1. デプロイ
$ sam deploy --template-file /home/ec2-user/environment/aws-cicd-sample/transformed.yaml --stack-name cicd-sampleBetaStack
  1. クリーンナップ(スタック削除)
$ aws cloudformation delete-stack --stack-name cicd-sampleBetaStack

コメント

  • Step4、5でsamコマンドを使ってパッケージ化&デプロイを実施しているが、こちらによると、Cloudformationコマンドでも同じらしい。
  • APIの定義はswaggerを利用。template.yaml(line:35)の中からswagger.yaml(line:34)を呼んでいる:
  Api:
    Type: 'AWS::Serverless::Api'
    Properties:
      StageName: Prod
      DefinitionBody:
        Fn::Transform:
          Name: AWS::Include
          Parameters:
            Location: swagger.yaml

自動

デモ稼働中。定義は↓

CI/CD pipeline

(aws-cicd-sample) takumi:~/environment/aws-cicd-sample (master) $ aws codepipeline get-pipeline --name aws-cicd-sample                                                                                                                                                          
{
    "pipeline": {
        "roleArn": "arn:aws:iam::XXXXXXXXXXXX:role/service-role/AWSCodePipelineServiceRole-ap-northeast-1-aws-cicd-sample", 
        "stages": [
            {
                "name": "Source", 
                "actions": [
                    {
                        "inputArtifacts": [], 
                        "name": "Source", 
                        "region": "ap-northeast-1", 
                        "actionTypeId": {
                            "category": "Source", 
                            "owner": "AWS", 
                            "version": "1", 
                            "provider": "CodeCommit"
                        }, 
                        "outputArtifacts": [
                            {
                                "name": "SourceRepo"
                            }
                        ], 
                        "configuration": {
                            "PollForSourceChanges": "false", 
                            "BranchName": "master", 
                            "RepositoryName": "aws-cicd-sample"
                        }, 
                        "runOrder": 1
                    }
                ]
            }, 
            {
                "name": "Build", 
                "actions": [
                    {
                        "inputArtifacts": [
                            {
                                "name": "SourceRepo"
                            }
                        ], 
                        "name": "CodeBuild", 
                        "region": "ap-northeast-1", 
                        "actionTypeId": {
                            "category": "Build", 
                            "owner": "AWS", 
                            "version": "1", 
                            "provider": "CodeBuild"
                        }, 
                        "outputArtifacts": [
                            {
                                "name": "CompiledCFNTemplate"
                            }
                        ], 
                        "configuration": {
                            "ProjectName": "aws-cicd-sample"
                        }, 
                        "runOrder": 1
                    }
                ]
            }, 
            {
                "name": "Beta", 
                "actions": [
                    {
                        "inputArtifacts": [
                            {
                                "name": "CompiledCFNTemplate"
                            }
                        ], 
                        "name": "CreateBetaChangeSet", 
                        "region": "ap-northeast-1", 
                        "actionTypeId": {
                            "category": "Deploy", 
                            "owner": "AWS", 
                            "version": "1", 
                            "provider": "CloudFormation"
                        }, 
                        "outputArtifacts": [], 
                        "configuration": {
                            "ActionMode": "CHANGE_SET_REPLACE", 
                            "ChangeSetName": "cicd-sampleChangeSet", 
                            "RoleArn": "arn:aws:iam::XXXXXXXXXXXX:role/cloudformation-lambda-execution-role", 
                            "Capabilities": "CAPABILITY_IAM", 
                            "StackName": "cicd-sampleBetaStack", 
                            "TemplatePath": "CompiledCFNTemplate::transformed.yaml"
                        }, 
                        "runOrder": 1
                    }, 
                    {
                        "inputArtifacts": [], 
                        "name": "ExecuteChangeSet", 
                        "region": "ap-northeast-1", 
                        "actionTypeId": {
                            "category": "Deploy", 
                            "owner": "AWS", 
                            "version": "1", 
                            "provider": "CloudFormation"
                        }, 
                        "outputArtifacts": [
                            {
                                "name": "AppDeploymentValues"
                            }
                        ], 
                        "configuration": {
                            "StackName": "cicd-sampleBetaStack", 
                            "ActionMode": "CHANGE_SET_EXECUTE", 
                            "ChangeSetName": "cicd-sampleChangeSet", 
                            "OutputFileName": "StackOutputs.json"
                        }, 
                        "runOrder": 2
                    }
                ]
            }
        ], 
        "artifactStore": {
            "type": "S3", 
            "location": "codepipeline-ap-northeast-1-XXXXXXXXXXXX"
        }, 
        "name": "aws-cicd-sample", 
        "version": 4
    }, 
    "metadata": {
        "pipelineArn": "arn:aws:codepipeline:ap-northeast-1:XXXXXXXXXXXX:aws-cicd-sample", 
        "updated": 1581311899.015, 
        "created": 1581062874.369
    }
}

各種サーバ設定

Redmine

暫定的にEC2上のコンテナで稼働。公式イメージはこちらから。

[ec2-user@ip-172-31-34-117 redmine]$ cat docker-compose.yml 
version: '3.1'

services:

  redmine:
    image: redmine
    restart: always
    ports:
      - 11111:3000
    environment:
      REDMINE_DB_MYSQL: db
      REDMINE_DB_PASSWORD: example

  db:
    image: mysql:5.7
    restart: always
    command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci
    environment:
      MYSQL_ROOT_PASSWORD: example
      MYSQL_DATABASE: redmine

SonarQube

暫定的にEC2上のコンテナで稼働。公式イメージはこちらから。公式サイトにはdocker-composeのサンプルがなかったので、下記の通りカスタマイズ。

[ec2-user@ip-172-31-34-117 sonarqube]$ cat docker-compose.yml 
version: '2'
services:
    sonarqube:
        image: sonarqube
        restart: always
        ports:
          - "22222:9000"
        volumes:
          - sonarqube_conf:/opt/sonarqube/conf
          - sonarqube_extensions:/opt/sonarqube/extensions
          - sonarqube_logs:/opt/sonarqube/logs
          - sonarqube_data:/opt/sonarqube/data
volumes:
  sonarqube_conf:
    driver: local
  sonarqube_extensions:
    driver: local
  sonarqube_logs:
    driver: local
  sonarqube_data:
    driver: local

Swagger

暫定的にEC2上のコンテナで稼働。GutHubのこちら参考。

[ec2-user@ip-172-31-34-117 swagger]$ cat docker-compose.yml
version: "3.3"
services:
  swagger-editor:
    image: swaggerapi/swagger-editor
    container_name: "swagger-editor"
    ports:
      - "8081:8080"

  swagger-ui:
    image: swaggerapi/swagger-ui
    container_name: "swagger-ui"
    ports:
      - "8082:8080"
    volumes:
      - ./swagger/openapi.json:/openapi.json
    environment:
      SWAGGER_JSON: /openapi.json
      # API_URL: ""

  swagger-api:
    image: danielgtaylor/apisprout
    container_name: "swagger-api"
    ports:
      - "8083:8000"
    volumes:
      - ./swagger/openapi.json:/openapi.json
    command: /openapi.json
    networks:
      swagger_link:
        aliases:
          - local.swagger.apisprout

  swagger-nginx:
    image: nginx:mainline-alpine
    container_name: "swagger-nginx"
    ports:
      - "8084:8084"
    volumes:
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf
    networks:
      swagger_link:
        aliases:
          - local.swagger.api

networks:
  swagger_link:
    external: true

ReDoc

暫定的にEC2上のコンテナで稼働。GutHubのこちら参考。

[ec2-user@ip-172-31-34-117 redoc]$ cat docker-compose.yml 
version: '2'
services:
  redoc:
    image: redocly/redoc
    restart: always
    ports:
      - "44444:80"
    volumes:
      - ./swagger.yaml:/usr/share/nginx/html/swagger.yaml
    environment:
      - SPEC_URL=swagger.yaml

残作業(ToDo)

コマンド

aws --endpoint-url=http://localhost:4572 s3api create-bucket --bucket aws-cicd-sample-managed-s3-bucket-artifacts

テストコード

curl -X POST http://127.0.0.1:3000/images -d '{"type":"image/jpeg","size":1}'

Redmine
https://qiita.com/nkenbou/items/e512b4aea9de40da606a

確かに Admin Area > Settings > Network > Outbound requests > Allow requests to the local network from hooks and services のチェックが入っていませんでしたので、このチェックを入れてテストすると…