AWS CodePipeline(CodeBuild)からRDSにアクセスする


はじめに

AWSのCodePipelineから利用するCodeBuildにて、検証および本番環境のスキーマを取得、そのスキーマを元にテストを実行したかったため、RDSに接続する必要がありました。そのため、VPCに配置する必要があり、さらにmysqldumpコマンド等を使用する必要もあったため、AWS標準で用意されているイメージではなく、カスタムイメージ作成し、利用することにしました。

その際に諸々設定した際の記事となります。

全体構成

配置するSubnetはPrivateなため、Proxyを経由してインターネットに接続します。

大まかな流れは以下

  1. CodePipelineを起動
  2. CodeCommitからソースダウンロード
  3. CodeBuild実行
    1. VPC(PrivateSubnet)に配置
    2. 事前に用意したカスタムイメージ上でBuildSpecを実行(Docker on Docker)
    3. RDS接続・テスト実行など
    4. ECRへPUSH
  4. CodeDeployでECSへデプロイ

今回は利用するカスタムイメージの作成や、buildspec/Dockerfileなど各ファイルの設定について記載します。(3-1~3)
※CodePipeline全体的な設定・ECSへのデプロイについては割愛します。

カスタムイメージの作成

最終的にアプリケーション用イメージが使用するものは以下のため、カスタムイメージではそれをインストールしておきます。
使用するベースイメージはUbuntu 20.04としました。

  • mariadb-client(mysqldumpで必要)
  • Docker
  • docker-compose
  • AWSCLI(v1)

Dockerfile

FROM ubuntu:20.04

RUN apt-get update 
RUN apt-get install software-properties-common -y
RUN add-apt-repository universe

# mysqldumpコマンド実行するためのコマンドインストール
RUN apt-get install -y mariadb-client

# Docker及びdocker-composeを実行するためにインストール
RUN apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    software-properties-common -y
RUN curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
RUN apt-key fingerprint 0EBFCD88
RUN add-apt-repository \
    "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
    $(lsb_release -cs) \
    stable"
RUN apt-get update 
RUN apt-get install -y docker-ce
RUN curl -L "https://github.com/docker/compose/releases/download/1.25.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
RUN chmod +x /usr/local/bin/docker-compose

# ECRにPUSHする必要があるためAWSCLIインストール
RUN apt-get install \ 
    unzip \
    python3-venv -y
RUN curl "https://s3.amazonaws.com/aws-cli/awscli-bundle.zip" -o "awscli-bundle.zip"
RUN unzip awscli-bundle.zip
RUN /usr/bin/python3.8 ./awscli-bundle/install -i /usr/local/aws -b /usr/local/bin/aws
RUN aws --version
  1. mysqldumpを実行するためにmariadb-clientをインストール
  2. Docker及びdocker-composeを起動・実行するためにインストール
    1. Dockerインストール
    2. docker-composeインストール
    3. インストールするだけだとDockerデーモンが立ち上がらないので、後述のdocker-composeにcap_addcapabilityを追加する
  3. AWSCLIを実行するために、インストール
    1. 既存のbuildspecに記述されてるコマンドではv2だと動かないので、v1を明示的に指定

docker-compose

docker-compose.yml
version: '3'
services:
  custom_image:
    cap_add:
      - NET_ADMIN
    tty: true
    image: ${IMAGE_URI}
    build:
      context: .
      dockerfile: Dockerfile
  1. cap_addNET_ADMINを許可しておく(Dockerデーモンを立ち上げるため)

buildspec

上記のDockerfiledocker-compose.ymlを利用してbuildspecからECRにPUSHする
※ECRにプッシュするためのbuildspecファイルの設定や、CodePipeline設定についてはここでは割愛します。

アプリケーション用ビルドプロジェクト設定

カスタムイメージ指定

該当のビルドプロジェクトから環境を編集する
ECRレポジトリから上記で作成した該当イメージを選択。
認証情報プルイメージはプロジェクトサービスロール。
またDockerを操作するので特権を付与する。

VPC配置

VPC及び、サブネットに配置する(Private配置)
RDSにアクセスする必要があるため、RDS接続用のセキュリティグループを設定する

環境変数は状況に応じて各種設定を行う

アプリケーション設定

上記で設定したビルドプロジェクトで動かすアプリケーション側の各ファイル(buildspec・Dockerfile・docker-compose)設定

buildspec

buildspec.yml
version: 0.2
proxy:
  upload-artifacts: yes
  logs: yes
phases:
  install:
    runtime-versions:
      docker: 18
  pre_build:
    commands:
      # Dockerデーモン起動+PROXY設定
      - export HTTP_PROXY=${HTTP_PROXY}
      - grep "#export http_proxy" /etc/default/docker
      - sed -i -e "/^#export http_proxy/c\export http_proxy=\"${HTTP_PROXY}\"" /etc/default/docker
      - grep "export http_proxy" /etc/default/docker
      - service docker start
      - service docker status
      # DBスキーマを取得
      - mysqldump --user=${DB_USER_NAME} --password=${DB_PASS} --quick --single-transaction -h readreplica-xxx.com targetdb -d > db/schema.sql
  build:
    commands:
      # テスト実行
      - docker-compose -f docker-compose.testing.yml build
      - docker-compose -f docker-compose.testing.yml run tester
      - $(aws ecr get-login --region ${AWS_DEFAULT_REGION} --no-include-email)
      省略…
  post_build:
    commands:
      省略…
artifacts:
  files: imagedefinitions.json

ポイントは以下
DockerfileでのイメージダウンロードなどProxyを経由するため/etc/default/dockerhttp_proxyを設定
(コメントアウトを外して、HTTP_PROXYを設定しなおす)

- export HTTP_PROXY=${HTTP_PROXY}
- grep "#export http_proxy" /etc/default/docker
- sed -i -e "/^#export http_proxy/c\export http_proxy=\"${HTTP_PROXY}\"" /etc/default/docker
- grep "export http_proxy" /etc/default/docker

Dockerのデーモンを起動(前述のNET_ADMINを設定していないと、ここでデーモンが起動しない)

- service docker start

リードレプリカに接続して、schemaを取得する

- mysqldump --user=${DB_USER_NAME} --password=${DB_PASS} --quick --single-transaction -h readreplica-xxx.com targetdb -d > db/schema.sql

テスト実行

- docker-compose -f docker-compose.testing.yml build
- docker-compose -f docker-compose.testing.yml run tester

docker-compose

同様にProxyを経由するように各種を変更
ここでは、buildspecから渡ってくるHTTP_PROXYargsでDockerfileに渡す

docker-compose.testing.yml
version: '3'
services:
  tester:
    build:
      context: .
      dockerfile: Dockerfile.testing
      args:
        - HTTP_PROXY=${HTTP_PROXY}
    links:
      - db_test
    environment:
      - UNIT_TEST_MYSQL_CONNECTION_STRING=root:password@tcp(db_test:3307)/db_test?parseTime=true&loc=Local&readTimeout=30s&writeTimeout=30s&timeout=30s
    command: go test ./... -v

  db_test:
    image: mysql:5.7.12
    environment:
      MYSQL_ROOT_PASSWORD: 'password'
      MYSQL_DATABASE: 'db_test'
    ports:
      - "3307:3307"
    command: mysqld --port 3307

Dockerfile

ARGHTTP_PROXYを設定する
今回はGoを用いているため、go mod downloadする際にProxyを経由するように設定

Dockerfile.testing
FROM golang:1.14 as builder

ARG HTTP_PROXY
省略…
RUN http_proxy=$HTTP_PROXY go mod download

省略…

まとめ

RDSに接続するために、PrivateSubnetへの配置を前提としている構成になっているため、Dockerや各言語が使用するコマンドを動かすために各所Proxyを設定していく必要があり、その辺が多少手間だと感じました。
とはいえ、動的にSchemaを取得し、テストの実行ができるようになったので、今後メンテナンスも含めて多少楽になるかと思っています。