【Amazon EKS】第三回 CodePipelineでEKSへのアプリケーションデプロイを自動化してみた!
投稿者:高橋 慶多
はじめに
こんにちは!ハイブリッドクラウド部の高橋です。
ハイブリッドクラウド部では、Amazon EKSについてのテックブログを投稿しています!
前回記事では「Nginxが起動するPodを作成し、AWS ALBを利用した負荷分散が出来るようになる」
手順をまとめました。
今回は「CodePipelineでJavaアプリケーションのEKSへのデプロイを自動化する」を実装します。
パイプラインはCodeCommit+CodeBuildで構築していきます。
まず、具体的にどんな手順を自動化したいかについてですが、
現在、EKS上に下図のような山の画像が表示されるアプリケーションが動いています。
Javaコードを一部編集すると、海の画像が表示されるアプリケーションになります。
本来、コードを編集した後にはコンパイル、warファイルの作成、イメージのビルド等の作業が必要なのですが、コードの編集を行うたびにそれらの作業を行うのは時間がかかってしまいます。
そこでCodePipelineを利用することで、コードの編集を行った後のそれら手順を自動化し、デプロイまでを迅速に行えるようにします。つまりコードの編集を行うだけで、山の画像が海の画像に変わるようにすることが今回の目的となります。
目次
- 事前準備
- CodeBuildでビルドプロジェクトを作成
- buildspec.ymlの作成
- CodeBuildサービスロールへの権限付与
- CodeBuildでkubectlを実行できるようにする
- CodePipelineでパイプラインを作成
- Javaアプリケーションのコードを編集してみる
- まとめ
事前準備
今回はCodeCommitをソースレポジトリとし、ローカルにレポジトリをクローンします。
クローン先でファイルの編集を行ってそれをCodeCommitにPushする形になります。
したがって、事前準備としてCodeCommitレポジトリをローカルにクローンする必要があります。
まずAWS CodeCommit の HTTPS Git 認証情報を生成します。
IAMユーザを選択し、セキュリティ認証情報タブのAWS CodeCommit の HTTPS Git 認証情報から、
認証情報を生成します。
ユーザー名とパスワードが表示されるため、メモしておきます。
次に、クローン時に必要なレポジトリのURLをコピーしておきます。
CodeCommitのレポジトリ一覧画面から、「HTTPS」をクリックしてURLをコピーできます。
ローカルから、下記のコマンドを実行します。
先ほどコピーしたURL、メモしておいたユーザー名とパスワードを入力します。
#レポジトリのクローン
git clone https://git-codecommit/xxxxxxxxxx
Username for 'https://git-codecommit.xxxxxxx':
Password for 'https://git-codecommit.xxxxxxx':
ローカルからレポジトリを見ることが出来るようになったと思います。
以上でCodeCommitレポジトリをクローンする手順は完了になります。
CodeBuildでビルドプロジェクトを作成
CodeBuildからビルドプロジェクトを作成します。
プロジェクト名を入力します。
ソースプロバイダは今回はCodeCommitになります。
ソースとするレポジトリを選択します。
マネージド型イメージを選択し、オペレーティングシステムは Amazon Linux 2 を選択します。
ランタイムはStandardで、今回イメージは aws/codebuild/amazonlinux2-x86_64-standard:corretto8を
選択しました。環境に応じて適切な設定を行ってください。
特権付与のボックスにチェックを入れます。
※CodeBuild内でdockerコマンドを実行する場合、ここでチェックを入れないとエラーが発生します。
新しいサービスロールを選択し、任意のロール名を入力します。
ビルド仕様はbuildspecファイルを使用する、を選択します。
ビルドプロジェクトを作成します。
buildspec.ymlの作成
buildspec.ymlとは、ビルドフェーズ時に実行するコマンドを記述したYAML形式のファイルのことです。
今回の場合はソースコードのコンパイル、イメージのビルド、ECRへのPUSH等を実行するコマンドをbuildspec.ymlに記述することになります。
buildspec.ymlは、基本的にはCodeCommitレポジトリのルートディレクトリに作成します。
buildspec.ymlの中身は以下の通りに記述します。
pre_build、build、post_buildの3つのフェーズに分けています。
pre_build段階ではビルド準備のためのコマンド、build段階では実際にビルドを行うコマンド、
post_build段階ではデプロイを行うコマンドを記述しています。
ご使用の環境に応じて変更箇所が存在する場合があります。
version: 0.2
phases:
install:
runtime-versions:
java: corretto8
pre_build:
commands:
- echo Preparing to build and push Docker image...
#codebuild上の環境にkubectlをインストール
- curl -O https://s3.us-west-2.amazonaws.com/amazon-eks/1.27.4/2023-08-16/bin/linux/amd64/kubectl
#kubectlコマンドに実行権限付与
- chmod +x ./kubectl
#kubectlコマンドをPATHに追加
- mkdir -p $HOME/bin && cp ./kubectl $HOME/bin/kubectl && export PATH=$HOME/bin:$PATH
#codebuild上の環境でkubectlを使用可能にする
- aws eks update-kubeconfig --region ap-northeast-1 --name クラスター名
#codebuildからECRにログイン
- aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin アカウントID.dkr.ecr.ap-northeast-1.amazonaws.com
#ECRリポジトリ(testapp)のURIを変数に格納
- export REPOSITORY_URI=471332609063.dkr.ecr.ap-northeast-1.amazonaws.com/testapp
#ビルドIDの最初の7文字をIMAGE_TAG変数に格納
- export IMAGE_TAG=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7)
- echo $IMAGE_TAG
build:
commands:
- cd sample_app
#codebuild環境上で既存のwarファイルを削除し、再ビルド
- mvn -X clean package
- cd target
#ビルドしたwarファイルをDockerfileがあるディレクトリへ移動
- mv sample-webapp.war ../image
- cd ../image
#codebuild環境上でDockerイメージをビルド
- docker build -t $REPOSITORY_URI:latest .
#ビルドしたDockerイメージにタグ付け
- docker tag $REPOSITORY_URI:latest $REPOSITORY_URI:$IMAGE_TAG
post_build:
commands:
- echo Build completed on `date`
#ECRにDockerイメージをPUSH
- docker push $REPOSITORY_URI:$IMAGE_TAG
- cd ../../yml
#deployment.yamlの"version"をIMAGE_TAGに置換
- sed -i -e "s/:version/:$IMAGE_TAG/g" ./deployment.yaml
- cat deployment.yaml
#deploymentを適用し、アプリケーションをEKSへデプロイ
- kubectl apply -f deployment.yaml
下記はdeployment.yamlの中身になります。
post_build段階で実行している”sed -i -e “s/:version/:$IMAGE_TAG/g” ./deployment.yaml”は、”image”の”:version”をIMAGE_TAGに置換しています。これによって、パイプラインが実行されるたびに、新しいバージョンのイメージがビルドされ、そのバージョンのイメージをEKSにデプロイすることができます。
# Deploymentリソースの定義に使用されるKubernetes APIのバージョンとグループ
apiVersion: apps/v1
# 作成するリソースの種類
kind: Deployment
# メタデータ
metadata:
name: tomcat-app # 作成するリソースの名前
namespace: sample-app # リソースを作成する名前空間
# リソースの仕様
spec:
replicas: 2 # Deploymentが管理するPodのレプリカ数
selector: # 適用するリソースの選択
matchLabels: # ラベルの一致を条件とする
app: tomcat
template: # 作成するpodの定義
metadata:
labels:
app: tomcat
spec:
containers: # pod内のコンテナの仕様
- name: tomcat-app # コンテナの名前
image: アカウントID.dkr.ecr.ap-northeast-1.amazonaws.com/testapp:version # コンテナイメージ
ports: # コンテナが公開するポート(内部向け)
- name: tcp
containerPort: 8080
CodeBuildサービスロールへの権限付与
CodeBuildで他のサービス(ECRやEKS)にアクセスするために、CodeBuildのサービスロールに権限を付与する必要があります。
以下の権限をCodeBuildのサービスロールに追加付与します。
これで、ECRとEKSへのアクセス権限を持ちます。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ecr:*",
"Resource": "arn:aws:ecr:ap-northeast-1:アカウントID:repository/レポジトリ名"
},
{
"Effect": "Allow",
"Action": "ecr:GetAuthorizationToken",
"Resource": "*"
},
{
"Effect": "Allow",
"Action": "eks:DescribeCluster",
"Resource": "arn:aws:eks:ap-northeast-1:アカウントID:cluster/クラスター名"
}
]
}
CodeBuildでkubectlを実行できるようにする
CodeBuildの中でkubectlを実行するには準備が必要です。
buildspec.yml内で記述したコマンドの実行権限は、CodeBuildのサービスロールということになります。
そのため、サービスロールをEKSのConfigMapに追加し、CodeBuildがクラスターにアクセスできるようにする必要があります。この設定をせずにkubectlが実行されると、下記のエラーが返ってくるはずです。
error: You must be logged in to the server (Unauthorized)
下記のコマンドで、aws-auth を編集することが出来ます。
kubectl edit -n kube-system configmap/aws-auth
CodeBuildのサービスロールをmapRoles内に以下のように追記します。
mapRoles: |
- rolearn: '<CodeBuildのサービスロールのARN>'
username: 'codebuild'
groups:
- system:masters
※注意点
CodeBuildサービルロールのARNはIAMロールページに表示されているものをそのままコピーしてはいけません。以下のように書き換える必要があります。
arn:aws:iam::アカウントID:role/service-role/codebuild-test_buildproject-service-role
↓
arn:aws:iam::アカウントID:role/codebuild-test_buildproject-service-role
CodePipelineでパイプラインを作成
CodePipelineからパイプラインを作成します。
パイプライン名を入力します。
新しいサービスロールを選択し、ロール名を設定します。
次へ行きます。
ソースステージの設定を行います。
ソースプロバイダーは AWS CodeCommitを選択します。
リポジトリ、ブランチを選択します。
検出オプションは、Amazon CloudWatch Eventsを選択して、次へ行きます。
ビルドステージの設定を行います。
AWS CodeBuildを選択し、先ほど作成したプロジェクトを選択します。
次へ行きます。
今回はデプロイステージは用意しないため、スキップします。
パイプラインを作成します。
以上がパイプラインの作成手順になります。
Javaアプリケーションのコードを編集してみる
パイプラインが作成完了したため、実際にJavaアプリケーションのコードを編集し、CodeCommitレポジトリに変更をPushしてみます。レポジトリへのPushを検知してパイプラインが起動し、ビルドが実行されることを確認します。
Javaコードの変更を、CodeCommitにPushする手順は以下のコマンドになります。
git add . #現在のディレクトリ配下の全ての変更をステージング
git commit -m "コミットメッセージ" #変更をコミット
git push #CodeCommitにPush
すると、CodeCommitに変更がPushされたことを検知して、パイプラインが走ります。
パイプラインの中で、buildspec.yml内で記述したコンパイルやイメージのビルド、Push等の手順が自動的に行われています。
パイプラインが成功することが確認できました。
ここでエラーが発生する場合は、「ログの表示」からエラー内容を確認して対応します。
山の画像が表示されていたのが、海の画像を表示するアプリケーションになっています。
Javaコードの変更をCodeCommitにPushするだけで、アプリのビルド・デプロイが自動的に行われることが確認できました。
まとめ
今回は、「CodePipelineでJavaアプリケーションのEKSへのデプロイを自動化する」手順をまとめました。
- CodeBuildでビルドプロジェクトを作成
- Buildspec.ymlの作成
- CodeBuildサービスロールへの権限付与
- CodeBuildでkubectlを実行できるようにする
- CodePipelineでパイプラインを作成
これらのステップにより、本来ならアプリのデプロイまでに多くの手順を踏まなければならないところを、コードの変更をCodeCommitにPushするだけで、デプロイすることが出来ました。この記事が皆さまのEKSやCI/CD環境の設定に役立つ一助となれば幸いです。この機会に、皆さまもぜひEKSを触ってみてください!
第4回では、「Podやノードのオートスケーリング」について記事を書く予定です!次回も楽しみにお待ちください!
AWS社とAWSソリューションプロバイダープログラム契約を結び、AWSのアカウントの手配から設計、環境構築、システム運用までワンストップのソリューションを提供いたします。
コンテナ技術には特に力を入れており、Amazon EKSだけでなく、Red Hat OpenShiftのソリューションもございます。
OpenShiftのソリューションページや、運用ソリューションであるNI+C Multicloud MSPの紹介ページもありますので、一読していただけますと幸いです。