強欲で謙虚なツボツボ

趣味の読書の書の方

備忘録(go-swaggerでAPIサーバを作る、gorm, air, dockerと共に)

GoでREST APIを作ります。

go-swaggerはyamlでWebAPIの定義をすることで、サーバーサイド・クライアントサイドのコードをコマンドの実行で生成してくれる。
今回はサーバーサイドだけ欲しいのでクライアントサイドは生成しない。
ただし、リクエストを受けた時にパラメータに従ってデータベースとやりとりする部分の処理(handler)は自身で実装する必要がある。
Railsとかでいうcontrollerのメソッドが中身空っぽな状態で必要なだけ自動生成され、その中身を自分で実装するみたいな感じ?

データベースはmysql

DockerでAPI用のコンテナとデータベース用のコンテナを起動させる。
また、コード編集でホットリロードさせるためにAPIの起動にはairを使う。

 

 

ディレクトリ構成

最終的にこうなる(ディレクトリと使うファイルのみ表示)
gen以下が自動生成されたコードで、ルートディレクトリからだとgo run api/server/gen/cmd/xxx/main.goで起動できる。
gen以下の生成されたコードは編集不可だが、restapi内のconfigure_xxx.goだけは編集可能。起動時処理やミドルウェアを記述したりするもので、このファイル存在時にgo-swaggerによるコード生成を行っても上書きされないから編集することができる。

root
  ├─ api
  │    ├─ server
  │    │    ├─ gen
  │    │    │    ├─ cmd
  │    │    │    │    └─ xxx
  │    │    │    │         └─ main.go
  │    │    │    ├─ models
  │    │    │    └─ restapi
  │    │    │         ├─ operations
  │    │    │         └─ configure_xxx.go
  │    │    └─ handlers
  │    │         └─ 自分で作成したhandler
  │    ├─ swagger
  │    │    └─ swagger.yaml
  │    ├─ .air.toml
  │    ├─ go.mod
  │    ├─ go.sum
  │    └─ Dockerfile
  ├─ config
  │    └─ config.go
  ├─ db
  │    └─ Dockerfile
  └─ docker-compose.yml

 

Docker

Dockerfileとdocker-compose.ymlを作成

# api/Dockerfile
FROM golang:1.16-alpine

RUN apk update && apk add git

# ホットリロードのためにairを導入
RUN go get github.com/cosmtrek/air

WORKDIR /usr/src/app
COPY api .
RUN go mod download && go mod verify

EXPOSE 8000
# db/Dockerfile
FROM mysql:5.7

COPY db/my.conf /etc/mysql/conf.d

EXPOSE 3306
# db/my.conf
[mysqld]
character-set-server=utf8mb4
collation-server = utf8mb4_bin
general_log=1
general_log_file=/var/log/mysql/mysql.log
log-error=/var/log/mysql/mysql-error.log

[mysqld]
character-set-server=utf8mb4

[client]
character-set-server=utf8mb4
# docker-compose.yml
version: "3"

services:
  api:
    build:
      context: .
      dockerfile: api/Dockerfile
    container_name: api
    environment:
      - DB_DRIVER=mysql
      - DB_DATABASE=dev
      - DB_USER=user
      - DB_PASSWORD=password
      - DB_HOST=db
      - DB_PORT=3306
    volumes:
      - api:/usr/src/app
    ports:
      - 8000:8000
    tty: true
    command: /bin/sh -c "air -c .air.toml"
    depends_on:
      - db

  db:
    build:
      context: .
      dockerfile: db/Dockerfile
    container_name: db
    environment:
      - MYSQL_DATABASE=dev
      - MYSQL_USER=user
      - MYSQL_PASSWORD=password
      - MYSQL_ROOT_PASSWORD=password
      - TZ=Asia/Tokyo
    ports:
      - 3306:3306

 

go-swagger導入

cd api
go mod init github.com/{githubのユーザー名}/{githubリポジトリ名}
go get -u github.com/go-swagger/go-swagger/cmd/swagger

 

swagger.yamlを作成

go-swaggerはOpenAPI2.0対応で、3.0は対応していないので注意

VScodeを使っているならば、Swagger Viewerというプラグインが便利

# api/swagger/swagger.yaml
---
swagger: "2.0"
info:
  version: 1.0.0
  title: Test
basePath: /api/v1
shemes:
  - http
paths:
  /user:
    get:
      tags:
        - user
      produces:
        - application/json
      responses:
        200:
          desciption: List of users
          schema:
            type: array
            items:
              $ref: "#/definitions/User"
        default:
          description: Unexpected error
          schema:
            $ref: "#/definitions/Error"
definitions:
  User:
    type: object
    properties:
      id:
        type: integer
        example: 1
      name:
        type: string
        example: テスト名前
      email:
        type: string
        example: test@gmail.com
      created_at:
        type: string
      updated_at:
        type: string
      deleted_at:
        type: string
  Error:
    type: object
    properties:
      code:
        type: integer
        example: 400
      message:
        type: string
        example: bad request

 

swagger.ymlからコードを生成

これによってgen以下にコードが生成される

cd api
mkdir -p server/gen
swagger generate server --strict-additional-properties -t ./server/gen -f ./swagger/swagger.yaml

 

.air.tomlの編集

起動するのに生成されたmain.goを参照するように変更し、hostとportを指定する
hostはデフォルトが127.0.0.0でDockerコンテナ外からアクセスするのに不便なので0.0.0.0を指定
portは起動するたびにランダムでホットリロードされるたびにポートが変化して面倒なので8000を指定

# api/.air.toml
cmd = "go build -o ./tmp/main ./server/gen/cmd/xxx"
full_bin = "APP_ENV=dev APP_USER=air ./tmp/main --host 0.0.0.0 --port 8000"

 

ハンドラを作成

この時点でdocker-compose up -dで起動できるが、localhost:8000/api/v1/userにアクセスすると「operation user.GetUser has not yet been implemented」と返ってくる
自動生成されたコードを見るとapi/server/gen/restapi/configure_xxx.goでapi.UserGetUserHandlerが定義されていないことがわかる。
なのでハンドラを作成して設定する。

# api/server/handers/user.go
type UserHandler struct {}

func NewUserHandler() UserHandler {
    return UserHandler{}
}

func (uh *UserHandler) GetUser(params user.GetUserParams) middleware.Responder {
    ver us []*models.User
    return user.NewGetUserOK().WithPayload(us)
}
# api/server/gen/restapi/configure_xxx.go
# configureAPI内に下記を追加
uh := handlers.NewUserHandler()
api.UserGetUserHandler = user.GetUserHandlerFunc(uh.GetUser)

これでlocalhost:8000/api/v1/userにアクセスするとhanderのWithPayloadで設定した空の配列が返ってくる

 

環境変数設定

docker-compose.ymlのenvironmentに記述した環境変数を読み込んでおく

# api/config/config.go
package config

type Config struct {
    DbDriver   string
    DbDatabase string
    DbUser     string
    DbPassword string
    DbHost     string
    DbPort     string
}

func NewConfig() Config {
    return Config{
        DbDriver:   os.Getenv("DB_DRIVER"),
        DbDatabase: os.Getenv("DB_DATABASE"),
        DbUser:     os.Getenv("DB_USER"),
        DbPassword: os.Getenv("DB_PASSWORD"),
        DbHost:     os.Getenv("DB_HOST"),
        DbPort:     os.Getenv("DB_PORT"),
    }
}

 

データベース接続

dockerで起動しているdbへ接続する。
接続情報は先の環境変数
今回はgormを使用する。

go get -u gorm.io/gorm
go get -u gorm.io/driver/mysql
# app/database/database.go
package database

type DatabaseClient struct {
    c *config.Config
}

func NewDatabaseClient(config *config.Config) DatabaseClient {
    return DatabaseClient{
        c: config,
    }
}

func (dc *DatabaseClient) ConnectDatabaseClient() *gorm.DB {
    driver := dc.c.DbDriver
    dsn := fmt.Sprintf(
        "%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local",
        dc.c.DbUser,
        dc.c.DbPassword,
        dc.c.DbHost,
        dc.c.DbPort,
        dc.c.DbDatabase,
    )
    db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
    if err != nil {
        log.Fatal("Failed to connect database: ", err.Error())
    }
    return db
}

func (dc *DatabaseClient) CloseDatabaseClient(db *gorm.DB) {
    sqlDb, _ := db.DB()
    if err := sqlDb.Close(); err != nil {
        log.Fatal("Failed to close connection database: ", err.Error())
    }
}
# api/server/gen/restapi/configure_xxx.go
# configureAPIを編集(下記は編集後の最終形態)
func configureAPI(api *operations.xxxAPI) http.Handler {
    // 下記を追記
    c := config.NewConfig()
    dc := database.NewDatabaseClient(&c)
    db := dc.ConnectDatabaseClient()
    
    // さっきhandler作成の時に追加した記述(引数にdbを持たせる)
    uh := handlers.NewUserHandler(db)
    api.UserGetUserHandler = user.GetUserHandlerFunc(uh.GetUser) 
    
    // 以下は初期のまま
    api.ServerError = errors.ServerError
    api.UseSwaggerUI() 
    api.JSONConsumer = runtime.JSONConsumer()
    api.JSONProducer = runtime.JSONProducer() 
    api.PreServerShutdown = func() {} 
    
    // CloseDatabaseClientを追記 
    api.ServerShutdown = func() { 
        dc.CloseDatabaseClient(db) 
    }
    
    return setupGlobalMiddleware(api.Serve(setupMiddleware)) }
# api/server/handlers/user.go
# データベースから情報を取得するように編集(下記は編集後の最終形態)

# DBを操作できるように変更
type UserHandler struct {
    db *gorm.DB
}

# 引数にdbを受け取るように変更
func NewUserHandler(db *gorm.DB) UserHandler {
    return UserHandler{
        db: db,
    }
}

# DBからデータを取得するように変更
func (uh *UserHandler) GetUser(params user.GetUserParams) middleware.Responder {
    ver us []*models.User
    res := uh.db.Find(&us)
    if err := res.Error; err != nil {
        return user.NewGetUserDefault(500)
    }
    return user.NewGetUserOK().WithPayload(us)
}

 

これでlocalhost:8000/api/v1/userにアクセスすれば、データベースに登録した情報を取得できる。

備忘録(データベース名、ユーザー名の変更)

データベース名とユーザー名の変更の仕方

 

データベース名

MySQL 5.2以上であれば、RENAME DATABASEが使えないので新たに作成して古いものを削除する
テーブルは新しいDBに属するように名前を変更

CREATE DATABASE new_db;
RENAME TABLE old_db.table1 TO new_db.table1, old_db.table2 TO new_db.table2, ... ;
DROP DATABASE db_old;

 

ユーザー名

RENAME USER old_name TO new_name;

備忘録(ECR + ECS で複数コンテナ)

各自のPCではdocker-composeを使ってAPI用のコンテナとフロント用のコンテナを作成して開発しているものを、AWS ECSとECRでデプロイする。

AWS上ではdocker-composeが使われるわけではなく、それぞれのコンテナを別々にdockerコマンドで起動しているような感じになる。
なので、コンテナの数だけECRでリポジトリ・ECSでタスクとサービスを設定する必要がある。
docker-compose.ymlで記述しているような環境変数やポートの設定はECR・ECSの設定としてコンソール上で入力していく。

 

 

参考

これらを見ながら作業をしました。

Dockerに慣れてきた人がECSで複数コンテナのデプロイをしてみる - Qiita

Dockerコンテナで作ったアプリをECS+RDSでデプロイする - Qiita

 

手順

Dockerはイメージがあって、それを元にコンテナを作成して、そのコンテナを起動する。
そして、イメージはECR・コンテナの作成と起動はECSで設定するので、ECRでリポジトリを作成してからECSでタスク定義とサービスの設定をする。

 

ECR

Create repository

ECRでDockerイメージを管理するリポジトリを作成する。

API用とフロント用で二つのDockerfileを元としたDockerイメージのために二つのリポジトリを作成する。

  • Visibility setttings:Private
  • Repository name:任意(プロジェクト名-コンテナ名とかが無難)
  • Tag immutability:Disabled
  • KMS encryption: Disabled

Createで作成完了。

 

Push

作成したリポジトリを見るとView push commandsとあるので、それに倣えばいい。
AWS CLIをインストールしておく必要がある。

aws ecr get-login-password --region {リージョン} | docker login --username AWS --password-stdin {AWSアカウントID}.dkr.ecr.{リージョン}/amazonaws.com
# AWS CLIのデフォルトプロファイル以外を使用する場合はプロファイルを指定する
# aws ecr get-login-password --region {リージョン} --pofile {プロファイル名} | docker login --username AWS --password-stdin {AWSアカウントID}.dkr.ecr.{リージョン}/amazonaws.com docker build -t {リポジトリ名} . # Dockerfileがルートディレクトリにない場合はパスを指定する
# dokcer build -t {リポジトリ名} -f {Dockerfileのパス} . dokcer tag {リポジトリ名}:latest {AWSアカウントID}.dkr.ecr.{リージョン}.amazonaws.com/{リポジトリ名}:latest docker push {AWSアカウントID}.dkr.ecr.{リージョン}.amazonaws.com/{リポジトリ名}:latest

 

ECS

クラスター作成→タスク定義→サービス設定

クラスターはdockerインストール済のEC2インスタンスだと思うと楽。
今回は、一つのクラスター内にAPI用のサービスとフロント用のサービスを作成する。

タスクはどのECRリポジトリのイメージを使用してコンテナを作成するかとか環境変数を設定したりする。

サービスはクラスター内でどのタスクを動かすかを決めるようなもの。docker-compose.ymlのservicesだと思うと楽かもしれない。(厳密には全然違うかもしれないけど)
frontendとbackendの二つのサービスになることが多いと思う。

Create Cluster

Step 1: Select cluster template

AWS Fargateでいい場合はNetworking onlyを選択。
Fargateは軽いEC2とでも思えばいい。
EC2みたいにssh接続はできないので異常時に中で確認したりはできない。あと、dockerコンテナのポートをホストで別のポートに結びつけることもできない。(8080:3000みたいな)
開発環境であればFargate、本番環境であればEC2でいいと思う。

Step 2: Configure cluster
  • Cluster name:任意
  • Create VPC:チェック
  • Tags:無記入
  • CloudWatch Container Insights:チェック

Createで作成完了。

Create new Task Definition

API用とフロント用で二つ作成する。
Step2のTask definition nameとTask execution role、Add containerの入力内容以外は同じ。

Step 1: Select launch type compatibility

たぶんクラスターと同じやつを選べばいい。
FARGATEを選択。

Step 2: Configure task and container definitions
  • Task definition name:任意
  • Requires compatibilities:FARGATE(Step 1で選んだやつ)
  • Task role:未選択(IAMロールが必要なら設定)
  • Network mode:awsvpc
  • Operating system family:Linux
  • Task execution role:なければ作成(2回目以降ならば初回で作ったものを選択)
  • Task memory (GB):0.5GB
  • Task CPU (vCPU):0.25 vCPU
  • Add Container:ボタンを押すとコンテナに関する入力欄が表示される
    Container name:任意
    Image:ECRのURIをコピー
    Port mappings:コンテナがListenするポート
    Environment variables:環境変数を設定(docker-compose.ymlのenvironmentやenv_fileの内容)
    その他の項目はそのままにした。
  • Service integration:未チェック
  • Proxy configuration:未チェック
  • Log router integration:未チェック
  • Volumes:未設定
  • Tags:無記入

Createで作成完了。

Create Service

API用とフロント用で二つ作成する。
Step1のTask DefinitionでAPI用・フロント用それぞれ対応するタスクを設定。
Step2のSecurity groupはAPI用とフロント用で分けるため別々の設定。

Step 1: Configure service
  • Launch type:FARGATE(クラスターと同じ)
  • Operating system family:Linux
  • Task Definistion:作ったタスクを選択
  • Platform version:LATEST
  • Cluster:作ったクラスタ
  • Service name:任意
  • Service type:REPLICA
  • Number of tasks:1
  • Minimum healty percent:100
  • Maximum percent:200
  • Deployment circuit breaker:Disabled
  • Deployment type:Rolling update
  • Enable ECS managed tags:チェック
  • Propagate tags from:Do not propagate
Step 2: Configure network
  • Cluster VPCクラスター作成時に自動作成されたVPCを選択
  • Subnets:クラスター作成時に自動生成されたサブネットを全て選択
  • Security groups:そのまま(新規作成)
  • Auto-assign public IP:ENABLED(あとで変更できないので注意)
  • Load balancer type:None(本番環境であればApplication Load Balancerを選択した方がいい)
  • Service discovery (optional):API用のみチェック
Service discovery (API用のみ)

各自のPCでdocker-composeを使用するときは、コンテナ内から別コンテナへアクセスのにコンテナ名を使用(http://api:8080みたいに)すればできる。
サービスディスカバリーはそのような設定をすることができ、Namespace nameにlocal・Service discovery nameにapiと設定すれば、local.api:portでフロント用コンテナ内からAPI用コンテナにアクセスできる。

  • Enable service discovery integration:チェック
  • Namespace:create new private namespace
  • Namespace name:任意
  • Configure service discovery service:Create new service discovery service
  • Service discovery name:任意
  • Enable ECS task health propagation:チェック
  • DNS record type:A
  • TTL:10
Step 3: Set Auto Scaling (optional)

本番であればちゃんと設定したほうがいいと思う。

  • Service Auto Scaling:Do not adjust th service's desired count
Step 4: Review

Step 1~3でしてきた設定を確認。

Create Serviceで作成完了。

クラスターでServicesがACITIVE・TasksがRUNNINGになっていることを確認できたらデプロイ完了。

 

Security Groups

これまでの過程でセキュリティグループが自動作成されているが、デフォルトではポートが80番しか空いていないので、コンテナがListenしているポートを開放する。
また、データーベースでRDSを使用する場合はAPI用のコンテナからのアクセスを許可する必要がある。

 

備考

今回作成したECS・ECRをgithubのプッシュを検知して自動デプロイさせる場合は、こちらを参照。(CodeBuild→CodePipeline)

taopo.hatenablog.com

taopo.hatenablog.com

 

備忘録(Go + Air in Docker)

dockerコンテナで go run main.go をした後に、ホスト側のローカルで修正しても go run し直すかdockerコンテナを再起動するしないと反映されない。
Airを使うと変更を随時反映させることができる。(ホットリロード・live reload)
Realizeというのもあるが使ったことはない。

 

Dockerfile

GitHub - cosmtrek/air: ☁️ Live reload for Go apps

FROM golang:1.16-alpine
RUN apk update && apk add git
RUN go get github.com/cosmtrek/air@latest
WORKDIR /usr/src/app
COPY go.mod go.sum .
RUN go mod download && go mod verify
COPY . .
EXPOSE 8080

 

docker-compose.yml

コマンドを go run main.go ではなく air -c .air.toml としてairで起動させる。
.air.tomlは設定ファイルで下記を編集。

air/air_example.toml at master · cosmtrek/air · GitHub

version: "3"

services:
  go:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: go
    volumes:
      - ./:./
    ports:
      - 8080:8080
    tty: true
    command: /bin/sh -c "air -c .air.toml"

あとは、dockerコンテナを起動すれば編集を随時反映してくれる。

備忘録(Python)

islower

全てが小文字で構成された文字列であればTrueを返す

'aiueo'.islower()
=> True
'Aiueo'.islower()
=> False

 

isupper

全てが大文字で構成された文字列であればTrueを返す

'AIUEO'.isupper()
=> True
'aIUEO'.isupper()
=> False

 

join

リストやタプルを連結して文字列を返す

''.join(['hello', 'world']
=> helloworld
' '.join(['hello', 'world']
=> hello world

 

重複削除

set(リスト)とするとリストの重複が削除されたセットを返す
list(set(リスト))とすればリストの重複を削除できる

list = ['hoge', 'geho', 'hoge']
set(list)
=> {'geho', 'hoge'}
list(set(list))
=> ['geho', 'hoge']

 

itertools.combinations

第一引数にリストやセットを第二引数に数値を与えると、全ての組み合わせをタプルで返す

list = [1, 2, 3]
for c in itertools.combinations(list, 2):
    print(c)
=> (1, 2)
   (1, 3)
   (2, 3)

備忘録(AWS CodeBuild + CodePipeline + GitHub)

GitHubで特定のブランチへのpushがあったときに、CodeBuildとCodePipelineで自動的にECSへのデプロイを行うためにCodeBuildとCodePipelineの設定をした。

フロントエンドとバックエンドで2つのGitHubリポジトリとECSサービスがあるので、それぞれフロントエンド用のCodeBuildとCodePipeline・バックエンド用のCodeBuildとCodePipelineの2つを作成する。

ECRとECRの設定はこちら。

taopo.hatenablog.com

 

 

手順

CodeBuild → CodePipeline

一方のCodeBuildとCodePipelineの設定をしたのちに他方を設定する。(自動で作成されるRoleを使い回す)

Create build project

  • Project name:適当に
  • Description:無記入
  • Build badge:未チェック
  • Enable concurrent build limit:未チェック
  • Additional configuration:無記入
  • Source provider:GitHub
  • Repository:Repository in my GitHub account
  • GitHub repository:任意のリポジトリを選択
  • Source version:webhookするブランチ名など
  • Additional configuration:そのまま
  • Webhook:チェック
  • Build type:Single build
  • Event type:PUSH
  • Start a build under these condition:無記入
  • Dont start a build under these condition:無記入
  • Environment image:Managed image
  • Operation system:Amazon Linux 2
  • Runtime(s):Standard
  • Image:aws/codebuild/amazonlinux2-x86_64_standard:3.0(一番下の選択肢)
  • Image version:Always use the latest image for this runtime version
  • Environment type:Linux
  • Privileged:チェック
  • Service role:New service role(2回目以降はExisting service role)
  • Role name:そのまま
  • Allow AWS CodeBuild to modify this service role so it can be used with this build project:チェック
  • Additional configuration:Environment variablesを設定し、それ以外はそのまま

    ここでの環境変数を後でbuildspec.ymlで使用する
    Name | Value | Type

    • AWS_DEFAULT_REGION                 | ap-northeast-1 | Plaintext
    • AWS_ACCOUNT_ID                         | ************       | Plaintext
    • AWS_ECR_REPOSITORY_NAME    | ************       | Plaintext
    • AWS_ECR_IMAGE_TAG                   | ************       | Plaintext
    • AWS_ECS_TASK_CONTAINER_NAME | ************       | Plaintext
  • Build specifications:Use a buildspec file
  • Buildspec name:無記入
  • Define batch configuration:無記入
  • Type:No artifacts
  • Encryption key:無記入
  • Cache type:No cache(キャッシュを設定するとビルド速度が上がるが、キャッシュによるビルド失敗が生じることもある)
  • CloudWatch logs:チェック
  • Group name:無記入
  • Stream name:無記入
  • S3 logs:未チェック

Create build projectで作成完了。

補足

GitHubは表示されるダイアログに従ってパスワードとかを入力すれば接続できる。OAuthでGitHubに接続するとPublic repositoryとRepository in my GitHub accountの選択が表示される。

 

IAM Role

New service roleを選択したので、新しくロールができている。
そのロールにECRへのアクセス権限を追加する。
Resourceを"*"としておけば、他のCodeBuildでも当該Roleを使用できる。

{
    "Effect": "Allow",
    "Resource": "*",
    "Action: [
        "ecr:BatchCheckLayerAvailability",
        "ecr:CompleteLayerUpload",
        "ecr:GetAuthorizationToken",
        "ecr:InitiateLayerUpload",
        "ecr:PutImage",
        "ecr:UploadLayerPart"
    ]
}

 

buildspec.yml

GitHubで管理するプロジェクトのルートにbuildspec.ymlを作成する。

version: 0.2

phases:
  pre_build:
    commands:
      - aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com
  build:
    commands:
      - docker build -t $AWS_ECR_REPOSITORY_NAME:$AWS_ECR_IMAGE_TAG . # この末尾の「.」を忘れないように
      - docker tag $AWS_ECR_REPOSITORY_NAME:$AWS_ECR_IMAGE_TAG $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$AWS_ECR_REPOSITORY_NAME:$AWS_ECR_IMAGE_TAG
  post_build:
    commands:
      - docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$AWS_ECR_REPOSITORY_NAME:$AWS_ECR_IMAGE_TAG
      - printf '[{"name":"%s","imageUrl":"%s"}]' $AWS_ECS_TASK_CONTAINER_NAME $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$AWS_ECR_REPOSITORY_NAME:$AWS_ECR_IMAGE_TAG > imagedefinitions.json

artifacts:
  files:
    - '**/*'

 

CodePipeline

Step 1 Choose pipeline setting

  • Pipeline name:任意
  • Service role:New service role(2回目以降はExisting service role)
  • Role name:自動で入力される
  • Allow AWS CodePipeline to create a service role so it can be used with this new pipeline:チェック
  • Advanced settings:そのまま

Step 2 Add source stage

Connectionは入力欄押下時に選択したいものがない場合は、Connect to GitHubをクリック。
ダイアログが表示されるので指示に従って接続する。

  • Source provider:GitHub(Version 2)
  • Connection:下記説明
  • Repository name:任意
  • Branch name:任意
  • Start the pipeline on source code change:チェック
  • Output artifact format:CodePipeline default

Step 3 Add build stage

  • Build provider:AWS CodeBuild
  • Region:Asia Pacific(Tokyo)
  • Project name:CodeBuild で作成済みのものを選択
  • Add environment variable:無記入
  • Build type:Single build

Step 4 Add deploy stage

  • Deploy provider:Amazon ECS
  • Region:Asia Pacific(Tokyo)
  • Cluster name:ECSで作成済みのClusterを選択
  • Service name:ECSで作成済みのServiceを選択
  • Image definitions file:無記入
  • Deployment timeout:無記入

Step 5 Review

Step 1~4までの入力を確認して、Create pipelineで作成完了。

 

 

これでgit pushすればwebhookによって自動的にCodeBuildでビルドされたDockerイメージがECRへプッシュされ、ECSのタスク定義がECRにプッシュされたDockerイメージを参照するように更新され、ECSのサービスが更新されたタスクを起動して自動デプロイが完了する。

 

 

備忘録(AWS CodePipeline)

GitHubで特定のブランチへのpushがあったときに、CodeBuildとCodePipelineで自動的にECSへのデプロイを行うためにCodePipelineの設定をした。

CodePipelineの設定の前にCodeBuildの設定をしておく。

taopo.hatenablog.com

 

 

Step 1 Choose pipeline setting

  • Pipeline name:適当に
  • Service role:New service role
  • Role name:自動で入力される
  • Allow AWS CodePipeline to create a service role so it can be used with this new pipeline:チェック

どのサービスでも作成するときはその時にService roleを作って後で好きなように編集する方がいいと思う。

Step 2 Add source stage

  • Source provider:GitHub(Version 2)
  • Connection:下記説明
  • Repository name:好きなのを選ぶ
  • Branch name:好きなのを選ぶ
  • Start the pipeline on source code change:チェック
  • Output artifact format:CodePipeline default

Connection

入力欄押下時に選択したいものがない場合は、Connect to GitHubをクリック。
ダイアログが表示されるので入力。

Connect to GitHubを押すと入力欄が出るから、そこでgitのリポジトリを選択。なければinstall new appでgit リポジトリを選べるようにする。

Step 3 Add build stage

  • Build provider:AWS CodeBuild
  • Region:Asia Pacific(Tokyo)
  • Project name:CodeBuild で作成済みのものを選択
  • Add environment variable:無記入
  • Build type:Single build

Step 4 Add deploy stage

  • Deploy provider:Amazon ECS
  • Region:Asia Pacific(Tokyo)
  • Cluster name:ECSで作成済みのClusterを選択
  • Service name:ECSで作成済みのServiceを選択
  • Image definitions file:無記入
  • Deployment timeout:無記入

Step 5 Review

  • Create

 

これでgit pushすれば自動的にECSへデプロイされる。