CodeDeployチュートリアルに失敗した記事のリベンジです。
wordpressとかdbとか余計なものをいれる過程でエラーして本質が見えなくなるのが嫌だったので内容を削ぎ落として超ミニマムなチュートリアルを勝手に作りました。
apacheが動いてるEC2にindex.htmlをデプロイするという簡単な進行でCodeDeployを理解していきます。
そもそもの理解。
上図、クラメソさんを参考にパクりました(本家参考:CodeDeployによるバージョン管理とステージング)
CodeDeployはデプロイ対象のデータをS3等に置いておき、手動/自動のタイミングでEC2へ流すというものです。その過程で、シェルを動かしたりなど細かな設定をS3に同時に格納するappspec.ymlに書くことで実現できます。(ここでEC2にS3への適切なアクセス権が必要。)
CodeDeployではアプリケーションという一番大きな単位がありその中にデプロイメントグループ、デプロイメントという粒度で構成されています。
デプロイメント
デプロイメントというのが、1回1回のデプロイに当たります。それぞれに結果や処理時間、エラーなどが見れます。
デプロイメントグループ
デプロイメントグループとは、どこにデプロイするのか(EC2)、どこにデータはあるのか(S3=リビジョン)、デプロイ方式は何かなどを設定しておき、これをもとにデプロイメントを行います。(デプロイメントの設計図のようなものかな?)
リビジョン
デプロイするデータがどこに置かれているかを指し示すものです。S3上に、デプロイするデータをバージョン管理していき、リビジョンでそれらの最新版を指定することで新しい物をデプロイすることができます。
アプリケーション
これらのデプロイ作業を機能単位などで分けるためにある?と思います。
まずはやってみる。ミニマムなチュートリアル。
IAMユーザを作成する。
アクセスキー/シークレットキーを設定しAWS CLIからAWSへアクセスできるユーザを1つ作成する必要あり。このユーザには少なくとも以下のポリシーを割り振ってください。
- AWSCodeCommitFullAccess (多分不要かも)
- AWSCodeDeployFullAccess
- AWSS3FullAccess
- AWSIAMFullAccess
EC2インスタンスを用意する。
Amazon Linuxを用いてインスタンスを作成。
AMI: Amazon Linux
インスタンスタイプ:任意のものでOK
IAMロール:`S3FullAccess`を含むロールを当てること。
EBS:デフォルトのままでOK
タグ:のちのち必要になるのでのでインスタンスには名前をつけてあげましょう。今回は`codedeploy`と命名。
セキュリティ:SSHとHTTP(S)が必要になります。以下を参考に。
SSH → マイIP(xx.xxx.xxx.xxx/32)
HTTP、HTTPS → 任意(0.0.0.0/0)
pemファイルはssh接続時に必要です。
EC2にApacheを入れる。
sshで侵入します。
$ ssh -i Download/xxx.pem ec2-user@xx.xxx.xxx.xxx
Warning: Permanently added 'xx,xxx,xxx,xxx' (ECDSA) to the list of known hosts.
__| __|_ )
_| ( / Amazon Linux AMI
___|\___|___|
https://aws.amazon.com/amazon-linux-ami/2018.03-release-notes/
13 package(s) needed for security, out of 26 available
Run "sudo yum update" to apply all updates.
$ sudo yum update -y
$ sudo yum install httpd -y
$ sudo service httpd start
Starting httpd: [ OK ]
IPv4 パブリックIPにアクセスするとApatchのデフォルトのページが出迎えてくれることを確認します。
EC2にCodeDeploy用のAgentを入れる。
前回ここがうまくいかないポイントの一つだったのですが、公式にちゃんとAmazon Linux用のセットアップ方法がありました。(参考:https://docs.aws.amazon.com/ja_jp/codedeploy/latest/userguide/codedeploy-agent-operations-install-linux.html)
なお、下記は東京リージョンでのケースなので、他のリージョンを使う場合には、install元のURIを適切なものに変える必要があります。(→一覧)
$ sudo yum install ruby
$ sudo yum install wget
$ cd /home/ec2-user
$ wget https://aws-codedeploy-ap-northeast-1.s3.ap-northeast-1.amazonaws.com/latest/install
$ chmod +x ./install
$ sudo ./install auto
$ sudo service codedeploy-agent status
The AWS CodeDeploy agent is running as PID 14515
EC2の準備はOKです。
デプロイするファイルを準備する。
ローカルでやることは3つです。
- AWS CLIを入れるorアップデートする。
- デプロイ対象のindex.htmlを作成する。
- CodeDeployのデプロイ設定を記述したappspec.ymlを作成する。
AWS CLIを入れるorアップデートする。
まだ入れていない場合は、以下公式参照。
https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-chap-install.html
$ sudo pip install --upgrade awscli
index.html/appspec.ymlを作成する。
$ mkdir testCodeDeploy
$ cd testCodeDeploy
$ touch index.html
$ vi index.html ←"Hello World!"とでも書いて保存。
$ touch appspec.yml
$ vi appspec.yml ←中身は下記。
version: 0.0
os: linux
files:
- source: /
destination: /var/www/html
今回は超ミニマムな内容なので、デプロイのみです。本当はhooks
でインストール前後や要所要所のタイミングを指定して任意のシェルを実行したりする設定も可能です。→この辺は今後やります。
-
source
はリビジョン(=S3バケット)の中のデプロイするファイルの位置を示します。 -
destination
にはデプロイ先を指定します。
S3バケットの準備
デプロイ対象を上げるS3バケットを作成します。
- バケット名はここでは
testcodedeploy
とします。 - パブリックアクセスはすべてブロック。(=デフォルトの設定)
バケットポリシーを以下のように設定します。
アクセス元を示すPrincipal
にはローカル環境のAWS CLI configureに設定したアクセスキー/シークレットキーのIAMユーザのARNを書くこと。後々、AccessDeniedで悲しい気持ちになります。
なお、IAMユーザのARNはIAMコンソール画面からコピペできます。
{
"Version": "2012-10-17",
"Id": "ExamplePolicy01",
"Statement": [
{
"Sid": "testcodedeploy",
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::xxxxxxxxxxxx:user/xxx",
"arn:aws:iam::xxxxxxxxxxxx:user/xxx"
]
},
"Action": [
"s3:GetObject",
"s3:GetBucketLocation",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::testcodedeploy/*",
"arn:aws:s3:::testcodedeploy"
]
}
]
}
デプロイ
現在、testCodeDeployディレクトリの中身は以下のようになっているはずです。
$ ls
appspec.yml index.html
まずは、アプリケーションを作成します。ここではTest
とします。
$ aws deploy create-application --application-name Test
{
"applicationId": "f33128d3-81bd-49f7-9b97-28f635995xxx"
}
デプロイ対象をzip化して、まるごと先ほど作成したS3バケットへ放り込みます。(1つのコマンドでできる。)
ここではファイル名をtestCodeDeploy.zip
とします。
$ aws deploy push \
--application-name Test \
--s3-location s3://testcodedeploy/testCodeDeploy.zip \
--ignore-hidden-files
To deploy with this revision, run:
aws deploy create-deployment --application-name Test --s3-location bucket=testcodedeploy,key=testCodeDeploy.zip,bundleType=zip,eTag=2dbc9aab3836f21317a9eed7a36f1xxx --deployment-group-name <deployment-group-name> --deployment-config-name <deployment-config-name> --description <description>
なお、この処理は以下のことをやっているのと同じです。(参考:CodeDeploy pushコマンドは裏で何をやっている?)
$ zip -r testCodeDeploy.zip .
$ aws s3api put-object --bucket testcodedeploy --key testCodeDeploy.zip --body testCodeDeploy.zip
$ aws deploy register-application-revision \
--application-name Test \
--s3-location bucket=testcodedeploy,key=testCodeDeploy.zip,bundleType=zip
デプロイメントグループの作成です。ここではTestGroup
という命名をします。
$ aws deploy create-deployment-group \
--application-name Test \
--deployment-group-name TestGroup \
--deployment-config-name CodeDeployDefault.OneAtATime \
--ec2-tag-filters Key=Name,Value=codedeploy,Type=KEY_AND_VALUE \
--service-role-arn arn:aws:iam::xxxxxxxxxxxx:role/CodeDeployServiceRole
{
"deploymentGroupId": "d4b9e016-b175-49eb-af9f-6ee6c0c55xxx"
}
deployment-config-name
ではデプロイ方式を選択しています。
service-role-arn
には、AWSがデフォルトで提供しているロールCodeDeployServiceRole
を使用。
いよいよデプロイです。
aws deploy create-deployment --application-name Test \
--deployment-config-name CodeDeployDefault.OneAtATime \
--deployment-group-name TestGroup \
--s3-location bucket=testcodedeploy,bundleType=zip,key=testCodeDeploy.zip
{
"deploymentId": "d-18TVA1BXD"
}
これで実際に対象のEC2の/var/www/html
下にindex.html
が置かれているはずです。
先ほどアクセスしたEC2のIPアドレスにブラウザからアクセスしてみましょう。Hello World!
が表示されれば成功です。
実際にCodeDeploy
コンソールからデプロイメント
を見てみると成功となっているでしょう。
おしまい
今後は、AutoScalingグループやlambdaへの応用、appspec.ymlの探索をやっていこうと思います。
追記
続編書きました。
トラブルシューティング
- create-applicationで失敗する。
$ aws deploy create-application --application-name Test
ModuleNotFoundError: No module named 'yaml'
$ pip install pyyaml
しろと書かれているページを発見。実行するも効果なし。
結局AWS CLIをアップデートしたところ解消しました。
-
deploy push
でAccessDeniedとなる。
$ aws deploy push \
--application-name Test \
--s3-location s3://testcodedeploy/testCodeDeploy.zip \
--ignore-hidden-files
Failed to upload '.' to 's3://testcodedeploy/testCodeDeploy.zip': An error occurred (AccessDenied) when calling the PutObject operation: Access Denied
AccessDeniedに弾き倒される。S3のバケットポリシーの設定なので、自身のAWS CLIのconfigureとそのIAMユーザがS3へアクエスできるバケットポリシー設定になっているかを確認してください。
- デプロイされない!(deploymentIdは返されている。)
→ CodeDeploy
コンソールからデプロイメント
を見て失敗していないか確認します。失敗の場合、エラー原因が出ているのでそれを修正します。
→ もしくは、EC2上からログを辿っても見られます。特にunknown error
などであればここを見てもいいかも。
$ tail -f -n 200 /var/log/aws/codedeploy-agent/codedeploy-agent.log
2019-12-17 13:30:46 ERROR [codedeploy-agent(14520)]: InstanceAgent::Plugins::CodeDeployPlugin::CommandPoller: Error during perform: Aws::S3::Errors::AccessDenied - Access Denied
こんな感じでエラーの理由がわかります。なお、上記は、EC2からS3へのアクセス許可がないためにでたエラーでした。EC2のロールにS3FullAccessをアタッチして再実行すると解決しました。