【CI/CDの導入】AWS CodePipeline(CodeCommit、CodeDeploy、Nginx、Auto Scaling、ALB の組み合わせ)を設定してみた

記事タイトルとURLをコピーする

こんにちは!技術4課のイーゴリです。

この記事では、AWS CodePipelineを使って、CodeCommit → CodeDeploy → Auto ScalingのEC2へのデプロイのプロセスを作ってみましたので、ご紹介したいと思います。

前回の記事で作成したリソースを使用しますので、まずは一番簡単なパイプラインについての記事を読んだほうが分かりやすいです。

blog.serverworks.co.jp

構成図

変更前(前回の記事の構成)

f:id:swx-korotkov:20220405105906p:plain

開発者:CodeCommitにコードをアップロードすると、CloudWatch Eventsがこれを検知して、CodePipelineは定義されたCodeDeployを起動し、EC2へデプロイされます。

エンドユーザー:インターネットから直接にEC2のApacheに接続します。

デメリット:

  • EC2がパブリックサブネットにあるため、EC2宛の不正アクセスの可能性が高まる(ソースIPの制限は可能だが、プライベートサブネットに置いたほうがベスト)
  • 冗長性/可用性はない
  • EC2のスケールアウトができない

前回(下記)の記事はCodePipeline+CodeCommit+CodeDeployの基本なので、あくまで練習環境として構築しました。今回の記事では、上記の環境のデメリットを改善したいと思います。

blog.serverworks.co.jp

変更後(今回構築構成)

f:id:swx-korotkov:20220414114433p:plain

CodeCommitにコードをアップロードすると、CloudWatch Eventsがこれを検知して、CodePipelineは定義されたCodeDeployを起動し、オートスケーリンググループのEC2へデプロイされます。

エンドユーザー:インターネットからApplication Load Balancer (ALB) 経由でEC2のNginxに接続します。

メリット:

  • 直接にEC2にアクセスはない(セキュリティが高まる)
  • オートスケーリンググループ及びApplication Load Balancer (ALB) による複数のAZの可用性がある
  • オートスケーリンググループによるEC2のスケールアウトができる

記事の目標

前回の記事で構築した環境の弱点を改善します。

前提条件

  • インストール済みのGitクライアント
  • パブリックサブネットにあるNATゲートウェイ
  • 構築されたEC2
  • 発行済みのIAMユーザー用のGit 認証情報

IAMユーザー用のGit 認証情報の生成手順

f:id:swx-korotkov:20220405121038p:plain

f:id:swx-korotkov:20220405121201p:plain

Code Commit リポジトリの作成

前回の記事で作成したCodeCommit リポジトリを使用しますので、このステップはスキップします。

新規でCode Commit リポジトリの作成をしたい場合、この記事の項目を参照してください。

CodeCommitリポジトリにサンプルコードを追加する

前回の記事でクローンした「index.html」及び「appspec.yml」のみを使用しますので、このステップはスキップします。

なお、「appspec.yml」で下記のように編集します。

変更前:

version: 0.0
os: linux
files:
  - source: /index.html
    destination: /var/www/html/
hooks:
  BeforeInstall:
    - location: scripts/install_dependencies
      timeout: 300
      runas: root
    - location: scripts/start_server
      timeout: 300
      runas: root
  ApplicationStop:
    - location: scripts/stop_server
      timeout: 300
      runas: root

変更後:

version: 0.0
os: linux
files:
  - source: /index.html
    destination: /var/www/html/
file_exists_behavior: OVERWRITE

※すでにindex.htmlがあるので、「file_exists_behavior: OVERWRITE」を追加しないと、「すでにファイルが存在するので、展開できません」というエラーが発生します。

The deployment failed because a specified file already exists at this location

上記のエラーが発生する時に、CodeDeployエージェント1.3.2以降の場合、appspec.ymlのfilesのセクションに「file_exists_behavior」のオプションを指定するとデプロイが実行できます。

新規で展開する場合、「file_exists_behavior: OVERWRITE」なしで問題ないです。

CodeBuild の設定

CodeBuild の設定はCodePipelineのパイプラインを作成する時に設定しますが、今回はhtmlのみを使うため、CodeBuidステップ及びbuildspec.yml ファイルの作成をスキップします。

f:id:swx-korotkov:20220406105400p:plain
CodeBuildのステップ

EC2のゴールドイメージの作成

CodeDeployエージェントのインストール

事前準備(IAMロール作成)

  • 「EC2InstanceDeployRole」というポリシーを追加し、IAMロールを作成します。 f:id:swx-korotkov:20220405130422p:plain f:id:swx-korotkov:20220405125728p:plain f:id:swx-korotkov:20220405130025p:plain f:id:swx-korotkov:20220405130036p:plain
  • IAMロールを対象のEC2に付与します。
  • EC2からのインターネットアクセスがあることを確認します。

エージェントのインストール

エージェントをインストールするには下記のURLの手順を使います。

docs.aws.amazon.com

対象EC2に入って、下記のコマンドを実行します。

$ sudo yum update
$ 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
$ sudo chmod +x ./install
$ sudo ./install auto
$ sudo service codedeploy-agent status
    The AWS CodeDeploy agent is running as PID 2629

注意点: 上記のwgetコマンドは東京リージョン向けのコマンドでしたが、東京リージョン以外の場合、 下記のコマンドをご参考ください。

wget https://bucket-name.s3.region-identifier.amazonaws.com/latest/install

<bucket-name>及び<region-identifier>はこちらに記載してありますので、ご参考ください。

ちなみに、EC2を作成する時に「ユーザーデータ」に上記のコマンドを入れると、便利です。

Nginxのインストール

$ sudo amazon-linux-extras install nginx1
$ systemctl status nginx.service
● nginx.service - The nginx HTTP and reverse proxy server 
   Loaded: loaded (/usr/lib/systemd/system/nginx.service; disabled; vendor preset: disabled) 
   Active: inactive (dead) 
$ sudo systemctl start nginx
$ systemctl status nginx.service
● nginx.service - The nginx HTTP and reverse proxy server
   Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; vendor preset: disabled)
   Active: active (running) since 諸略

f:id:swx-korotkov:20220413172430p:plain

nginxの自動起動を設定する

$ sudo systemctl enable nginx

確認

$ sudo systemctl list-unit-files | grep nginx
 nginx.service                                 enabled 

f:id:swx-korotkov:20220413172700p:plain

ブラウザでパブリックIPにアクセスしますと、下記の画面が表示されます。

f:id:swx-korotkov:20220413173220p:plain

今回の記事では、appspec.ymlで指定した「/var/www/html/」のパスを、Nginxで設定したいため、「nginx.conf」ファイルを編集します。

$ sudo vi /etc/nginx/nginx.conf
 
    server { 
        listen       80; 
        listen       [::]:80; 
        server_name  _; 
        root         /var/www/html/;  ← rootフォルダを設定

f:id:swx-korotkov:20220413173851p:plain

再起動

systemctl restart nginx 

/var/www/html/にあるindex.htmlに変更されましたので、EC2のゴールドイメージの準備は完了です!

f:id:swx-korotkov:20220413174111p:plain

AMIの取得

f:id:swx-korotkov:20220413180041p:plain

[イメージ名]を記載した後で、[イメージを作成]をクリックします。

f:id:swx-korotkov:20220413180607p:plain f:id:swx-korotkov:20220413180638p:plain

注意:EC2のAMI取得時に再起動されますので、再起動なしでAMI取得をしたい場合、[再起動しない]のところに、チェックを入れます。 f:id:swx-korotkov:20220413180419p:plain

Application Load Balancer (ALB) の作成

ターゲットグループの作成

[サービス]>[EC2]>[ターゲットグループ]>[ターゲットグループの作成]をクリックします。

f:id:swx-korotkov:20220414103948p:plain

f:id:swx-korotkov:20220414104541p:plain

プロトコルバージョンやヘルスチェックの設定を必要に応じて設定してください。

f:id:swx-korotkov:20220414104450p:plain

私の場合、デフォルトのまま設定し、[次へ]をクリックします。

f:id:swx-korotkov:20220414104826p:plain

インスタンスを追加せずに[ターゲットグループの作成]をクリックします。

f:id:swx-korotkov:20220414105118p:plain

完了です。

f:id:swx-korotkov:20220414115950p:plain

ロードバランサーの作成

[サービス]>[EC2]>[ロードバランサー]>[ロードバランサーの作成]をクリックします。

f:id:swx-korotkov:20220414102816p:plain

Application Load Balancerを選択します。

f:id:swx-korotkov:20220414105458p:plain

パブリックサブネットに置きます。

f:id:swx-korotkov:20220414115145p:plain

f:id:swx-korotkov:20220414115107p:plain

リスナーを設定し、上記で作成したターゲットグループを選択します。

f:id:swx-korotkov:20220414120157p:plain

事前にターゲットグループを作成せずにロードバランサーの作成の画面でターゲットグループを作成した場合、ターゲットグループの一覧にないので、更新ボタンを押してください。

f:id:swx-korotkov:20220414120539p:plain

注意点:今回の記事ではリスナーとしてHTTP(暗号化なし)を使っていますが、非推奨となりますので、HTTPS(暗号化あり)を使ってください。

[ロードバランサーの作成]をクリックします。

f:id:swx-korotkov:20220414121034p:plain

EC2起動テンプレートの作成

AutoScaling Group のためにEC2起動テンプレートの作成を行います。

[サービス]>[EC2]>[起動テンプレート]>[起動テンプレート を作成]をクリックします。

f:id:swx-korotkov:20220414121453p:plain

[Auto Scaling のガイダンス]は任意項目です。

f:id:swx-korotkov:20220414121811p:plain

上記に作成したAMIを選択します。

f:id:swx-korotkov:20220414122033p:plain

f:id:swx-korotkov:20220414124907p:plain

必要に応じて、他の設定を行ってください。

ここで前回作成したIAMロール(EC2-CodeDeploy)を付与します。

f:id:swx-korotkov:20220414125301p:plain

[起動テンプレート]を作成します。

f:id:swx-korotkov:20220414130102p:plain

完了です。

Auto Scaling グループの作成

起動テンプレートの作成が完了しましたら、該当の起動テンプレートを選択し、[アクション]>[Auto Scaling グループを作成]をクリックします。

f:id:swx-korotkov:20220414144129p:plain

f:id:swx-korotkov:20220414144318p:plain

f:id:swx-korotkov:20220414144400p:plain

下記の画面で、プライベートサブネットを選択します。

f:id:swx-korotkov:20220414144633p:plain

f:id:swx-korotkov:20220414145434p:plain

インスタンスタイプなどの箇所は必要に応じて設定を行い、[次へ]をクリックします。

f:id:swx-korotkov:20220414154511p:plain

f:id:swx-korotkov:20220414154858p:plain

既存のロードバランサーにアタッチします。

f:id:swx-korotkov:20220414150510p:plain

ヘルスチェックの[ELB]の選択肢にもチェックを入れます。

f:id:swx-korotkov:20220414151430p:plain

なお、[ヘルスチェックの猶予期間]のところで、パイプラインが完了するまでの時間を考慮した上、設定する必要があります。そして[次へ]をクリックします。

f:id:swx-korotkov:20220414151605p:plain

オートスケーリングの設定は必要に応じて設定する必要があります。

  • EC2数を固定したい場合、下記の画面の3つの欄で同じ数値を入力します。

f:id:swx-korotkov:20220415142041p:plain

f:id:swx-korotkov:20220414152116p:plain

  • 私の場合、すぐ2台起動したいのと、最小のEC2数:2台、最大のEC2数:3台で設定します。

f:id:swx-korotkov:20220414152317p:plain

平均CPU使用率は80%を超える場合、3台まで増やせるという設定を行います。

f:id:swx-korotkov:20220414152416p:plain

他の設定は任意ですので、最後までデフォルト値のまま進みます。

f:id:swx-korotkov:20220414152657p:plain

f:id:swx-korotkov:20220414152700p:plain

f:id:swx-korotkov:20220414152705p:plain

オートスケーリンググループのステータスで「キャパシティーの更新」が表示されますので、[EC2]の[インスタンス]欄で、EC2が起動されます。

f:id:swx-korotkov:20220414155452p:plain

f:id:swx-korotkov:20220415142737p:plain

CodeDeploy の設定

前回の記事では、CodeDeploy の設定を設定したため、ご参考ください。

今回の記事では、EC2のAutoScaling Groupのために既存の[MyApp1]アプリケーションで新規のデプロイグループを作成します。

既存の[MyApp1]をクリックし、デプロイグループを作成します。

f:id:swx-korotkov:20220414160916p:plain

f:id:swx-korotkov:20220414161116p:plain

既存のIAMロールを選択します。

f:id:swx-korotkov:20220414161222p:plain

デプロイタイプのデプロイ方法は必要に応じて設定しますが、私は[インプレース]のまま進みます。[環境設定]で[Amazon EC2 Auto Scaling グループ]を選択します。そして該当のASG(私の場合、[asg-1])を選択し、次に進みます。

f:id:swx-korotkov:20220414161329p:plain f:id:swx-korotkov:20220414161727p:plain 

CodePipeline の設定

前回の記事でPipelineを作りましたので、新規作成をスキップしますが、新規で作成する場合、前回の記事をご参考ください。

CodePipeline の設定の修正

CodePipelineの修正をし、1台のEC2の構成からAuto Scaling + ALB の構成に切り替えます。

[サービス]>[CodePipeline]>該当のパイプラインをクリックします。

f:id:swx-korotkov:20220414162558p:plain

[編集]をクリックします。

f:id:swx-korotkov:20220414162642p:plain

[Deploy]の[ステージを編集する]をクリックします。

f:id:swx-korotkov:20220414162822p:plain

編集マークをクリックします。

f:id:swx-korotkov:20220414163443p:plain

デプロイグループで「MyApp1」(1台のEC2)から「MyApp2」(Auto Scaling グループ + ALB)に変更し、[完了]をクリックします。

f:id:swx-korotkov:20220414162945p:plain

「完了」をクリックします。

f:id:swx-korotkov:20220414163218p:plain

もう一度「完了」をクリックします。

f:id:swx-korotkov:20220414163601p:plain

[保存]をクリックします。

f:id:swx-korotkov:20220414163658p:plain

[変更をリリースする]をクリックします。

f:id:swx-korotkov:20220414163757p:plain

[リリースする]をクリックします。

f:id:swx-korotkov:20220414163838p:plain

正常性の確認

ターゲットグループに入ると、起動されているEC2が[healthy]の状態になっています。

f:id:swx-korotkov:20220414164544p:plain

ロードバランサーのDNS名でアクションすると、「index.html」は正常に稼働しています。

f:id:swx-korotkov:20220414165137p:plain

例えば、CodeCommitで何かの変更を行い、もう一度プッシュします。

% cd test-rep
% git add .
% git commit -m "5rd commit"
% git push

※「5rd」の「rd」を削除し忘れたため、正しい英語ではありませんので、真似しないでくださいねー(笑)

[CodeDeploy]>[デプロイメント]>デプロイ履歴の該当のデプロイIDをクリックします。

f:id:swx-korotkov:20220414184915p:plain

[デプロイのライフサイクルイベント]の[イベント]の[View events]をクリックします。

f:id:swx-korotkov:20220414185228p:plain

f:id:swx-korotkov:20220414165731p:plain

確認が完了です!

注意点

パブリックサブネットにNATゲートウェイ/NATインスタンスがないとデプロイの処理中に、CodeDeploy Agentのエラーが発生しますので、ご注意ください。

f:id:swx-korotkov:20220414183925p:plain

エラー内容:

CodeDeploy agent was not able to receive the lifecycle event. Check the CodeDeploy agent logs on your host and make sure the agent is running and can connect to the CodeDeploy server.

f:id:swx-korotkov:20220414184244p:plain f:id:swx-korotkov:20220414184404p:plain

以上、御一読ありがとうございました。

本田 イーゴリ (記事一覧)

カスタマーサクセス部

・2024 Japan AWS Top Engineers (Security)
・AWS SAP, DOP, SCS, DBS, SAA, DVA, CLF
・Azure AZ-900
・EC-Council CCSE

趣味:日本国内旅行(47都道府県制覇)・ドライブ・音楽