CodeDeploy pushコマンドは裏で何をやっている?
AWSのデプロイ自動化サービスCodeDeployのチュートリアルでは、デプロイするコードを
$ aws deploy push
コマンドでS3にアップロードし、(アップロードしたコードベースは「リビジョン」と呼ばれます)、管理画面からリビジョンを指定してデプロイを実行するのが一般的です。
では、この$ aws deploy push
コマンドは裏で何をやっているのでしょうか?
deploy push
を実行してみる
$ aws deploy push
を実際に実行してみましょう。
$ aws deploy push --application-name foo --description "test" --s3-location s3://YOUR-BUCKET/cd/test.zip To deploy with this revision, run: aws deploy create-deployment --application-name foo --s3-location bucket=YOUR-BUCKET,key=cd/test.zip,bundleType=zip,eTag="21e51f92a0c85eca8a1cc1d514e85061" --deployment-group-name <deployment-group-name> --deployment-config-name <deployment-config-name> --description <description>
リビジョンをアップロードするpushコマンドを実行すると、デプロイ実行するコマンドがレスポンスとして表示されました。
aws cliのコマンド実行時に--debug
オプションをつけると、AWS に
- S3 の PutObject
- CodeDeploy の RegisterApplicationRevision
という2つのAPIを投げていることがわかります。
さらにAWS CLIのコードを眺めてみると、
- ローカルファイルシステムのソースコードを ZIP 形式でバンドル
- S3 に ZIP ファイルを PutObject
- PutObject したS3オブジェクトを アプリケーションと紐付け
していることがわかります。
deploy push
の処理を個別実行してみる
deploy push
コマンド実行時に、背後で実行されている処理を個別に実行してみましょう。
ローカルファイルシステムのソースコードを ZIP 形式でバンドル
カレントディレクトリ以下を ZIP アーカイブ化します。
$ zip -r test.zip . updating: .test (stored 0%) updating: appspec.yml (deflated 54%) updating: index.html (deflated 47%) updating: LICENSE.txt (deflated 64%) updating: scripts/ (stored 0%) updating: scripts/install_dependencies (stored 0%) updating: scripts/start_server (stored 0%) updating: scripts/stop_server (deflated 17%)
S3 に ZIP ファイルを PutObject
S3 にアップロードします。
$ aws s3api put-object --bucket YOUR-BUCKET --key cd/test.zip --body test.zip { "ETag": "\"240d16519925272a9bd463b8af5ee1ba\"" }
PutObject したS3オブジェクトをアプリケーションと紐付け
deploy register-application-revision
コマンドで CodeDeployのアプリケーションとリビジョンを紐付けます。
$ aws deploy register-application-revision \ --application-name foo \ --description "register zip revision" \ --s3-location bucket=YOUR-BUCKET,key=cd/test.zip,bundleType=zip
紐付け時にはオプションでS3オブジェクトのETagやバージョンを渡す事もできます。
ETagを渡すと、オブジェクトのETagバリデーションが行われます。 バージョンを指定しないと、最新のバージョンが利用されます。
紐付けられていることを確認します。
$ aws deploy list-application-revisions --application-name foo { "revisions": [ { "revisionType": "S3", "s3Location": { "bundleType": "zip", "bucket": "YOUR-BUCKET", "key": "cd/test.zip" } } ] }
デプロイを実行
デプロイメントグループとリビジョンを指定してデプロイします。
$ aws deploy create-deployment \ --application-name foo \ --deployment-config-name CodeDeployDefault.OneAtATime \ --deployment-group-name foo \ --description "zip" \ --s3-location bucket=YOUR-BUCKET,bundleType=zip,key=cd/test.zip { "deploymentId": "d-GLEG3CLBE" }
デプロイステータスを確認します
$ aws deploy get-deployment --deployment-id d-GLEG3CLBE { "deploymentInfo": { "applicationName": "foo", "status": "Succeeded", "deploymentOverview": { "Failed": 0, "InProgress": 0, "Skipped": 0, "Succeeded": 1, "Pending": 0 }, "description": "zip", "deploymentConfigName": "CodeDeployDefault.OneAtATime", "creator": "user", "deploymentId": "d-GLEG3CLBE", "ignoreApplicationStopFailures": false, "deploymentGroupName": "foo", "createTime": 1460183482.584, "completeTime": 1460183499.275, "revision": { "revisionType": "S3", "s3Location": { "bundleType": "zip", "bucket": "YOUR-BUCKET", "key": "cd/test.zip" } } } }
ステータスは正常系であればInProgress
-> Succeeded
と遷移します。
ZIP形式以外でリビジョン登録する
RegisterApplicationRevision
APIのbundleType
を見るとわかるように、リビジョンのファイル形式は
- tar
- tgz(tar+gzip)
- zip
に対応しています。
tgz形式でリビジョン登録してみましょう。
ローカルファイルシステムのソースコードを tgz 形式でバンドル
$ tar cvzf foo.tgz * .??* a LICENSE.txt a appspec.yml a index.html a scripts a scripts/install_dependencies a scripts/start_server a scripts/stop_server a .test
S3 に tgz ファイルを PutObject
$ aws s3api put-object --bucket YOUR-BUCKET --key cd/foo.tgz --body foo.tgz { "ETag": "\"18fb40b3f744bf1b551e33204a1a7a59\"" }
PutObject したS3オブジェクトをアプリケーションと紐付け
$ aws deploy register-application-revision \ --application-name foo \ --description "register tgz bundle" \ --s3-location bucket=YOUR-BUCKET,key=cd/foo.tgz,bundleType=tgz $ aws deploy list-application-revisions --application-name foo { "revisions": [ { "revisionType": "S3", "s3Location": { "bundleType": "tgz", "bucket": "YOUR-BUCKET", "key": "cd/foo.tgz" } }, { "revisionType": "S3", "s3Location": { "bundleType": "zip", "bucket": "YOUR-BUCKET", "key": "cd/test.zip" } } ] }
デプロイを実行
$ aws deploy create-deployment \ --application-name foo \ --deployment-config-name CodeDeployDefault.OneAtATime \ --deployment-group-name foo \ --description "tgz" \ --s3-location bucket=YOUR-BUCKET,bundleType=tgz,key=cd/foo.tgz { "deploymentId": "d-XB5OOPKBE" } $ aws deploy get-deployment --deployment-id d-XB5OOPKBE { "deploymentInfo": { "applicationName": "foo", "status": "Succeeded", "deploymentOverview": { "Failed": 0, "InProgress": 0, "Skipped": 0, "Succeeded": 1, "Pending": 0 }, "description": "tgz", "deploymentConfigName": "CodeDeployDefault.OneAtATime", "creator": "user", "deploymentId": "d-XB5OOPKBE", "ignoreApplicationStopFailures": false, "deploymentGroupName": "foo", "createTime": 1460185839.647, "completeTime": 1460185857.264, "revision": { "revisionType": "S3", "s3Location": { "bundleType": "tgz", "bucket": "YOUR-BUCKET", "key": "cd/foo.tgz" } } } }
bundleType
をzipなどと間違えると、CodeDeploy エージェントはリビジョンがZIPバンドルであると判断するため "Zip end of central directory signature not found" というようなエラーが発生します。
まとめ
CodeDeployのpush
コマンドは
- コードベースをバンドル
- バンドルをS3にアップロード
- アプリケーションとS3オブジェクトの紐付け
を行っており、各ステップで分解できることがわかりました。
例えばsbtなどのビルドツールでバンドルする仕組みがあるアプリケーションは、既存の仕組みを活かしたまま AWS との連携処理を追加すれば CodeDeploy対応できます。
またCIツールを使っている場合、各ステップにブレイクダウンしたタスクを作成しておくと、デプロイパイプラインの変更やトラブルシュートがしやすくなります。