Agency事業部にてアプリケーションエンジニアをしている山﨑です
今回は、EC2へのデプロイ環境を一元化するため、Cloud9上に環境構築を行った話です
AWSサービスやインフラにあまり触れたことのない方向けに、一連の手順を丁寧に記述してみました
- 背景
- おおまかな手順
- 前提となる環境
- 実装
- まとめ
背景
背景は、先日公開された松井さんの記事と同一です
定期的に発生する認証基盤やVPNの変更、PC交換によるマシンアーキテクチャの変更などによって、ローカル環境からのデプロイ作業が大きな影響を受けていました
そこで、とりあえず「ローカル環境からのデプロイ」をなくすことにしました
要件は下記です
- AWS上の本番環境・検証環境に手動デプロイするための共有マシン環境を構築する
- GitLab/GitHubをSSH経由で参照する
- デプロイにDocker, Docker Composeを使う
- 異なるVPCに存在するEC2インスタンスにSSH接続する
- チーム内の複数のエンジニアにマシン環境を共有する
(余談) なぜCloud9にデプロイ環境を構築することにしたか
Docker環境の作成とGit管理は既に行っており、マシン・ネットワークの問題を解消すれば当面の課題は解決する状況でした
CD(継続的デプロイ)導入への繋ぎとして、簡単に課題を解決できるCloud9環境の構築を行うことにしました
事実、作業は1時間ほどで完了しました
おおまかな手順
- Cloud9環境を作成する
- GitLab/GitHub上のリポジトリをClone, Pullする
- ディスク容量を拡張する
- Docker, Docker Composeにてコンテナを立ち上げる
- デプロイ先のEC2インスタンスへのSSH通信を設定する
- 作成したCloud9環境を複数のユーザに共有する
- おまけ: Cloud9環境からAWSリソースへのアクセスを制限する
前提となる環境
AWS
- ネットワーク環境*1は作成済み
- デプロイ先のEC2インスタンスにパブリックIPを割り当て済み
AWS Single Sign-On (AWS SSO)
が導入されている- 開発者はフェデレーションユーザとしてAWSマネジメントコンソールにアクセスする
その他
- コードはGitリポジトリで保守してGitLab/GitHubにて管理している
Dockerfile
,docker-compose.yml
にて実行環境作成済み
実装
【1】 Cloud9環境を作成する
Cloud9環境を作成します
AWS Cloud9 を開き、[環境を作成] を押下します
画面に従ってポチポチと作成していきます
Cloud9環境の[名前]、[説明]を設定します ※後から変更可能
環境タイプは「新しいEC2インスタンス」を選択します
インスタンスタイプを選択
必要なメモリ、CPUのサイズを選択します
小さめに選んでおいて、後で変更するのも有り
インスタンスタイプは t
(汎用・安価), m
(汎用), c
(コンピューティング最適化) から選択可能です
常時稼働しなくて良いならt
を選ぶのが無難です
参考) インスタンスタイプ - Amazon EC2 | AWS
プラットフォームを選択
Amazon Linux 2
, Amazon Linux 2023
, Ubuntu Server 22.04 LTS
から選択可能です
Amazon Linux 2
は2025年6月でサポートが終了するのでAmazon Linux 2023
がおすすめです
ネットワーク設定 - 接続タイプを選択
どちらを選択しても動作は大差ありません
今回は社内統制の都合上SSH
を選択しているが、AWS System Manager (SSM)
の方がセキュアでおすすめです
AWS System Manager (SSM)
の注意
- 「既存のインスタンス」を用いてCloud9環境を構築する場合は選択不可
- 特定のサブネットを選択したい場合は選択不可
- サブネット設定の[パブリック IPv4 アドレスを自動割り当て]が「いいえ」の場合、パブリックIPアドレスが自動で割り当てられないことに注意
(インターネットに接続できなくなる)
ネットワーク設定 - VPC設定
パブリックサブネット を選択
「パブリックサブネット」を選択すると、サブネット設定に関わらずパブリックIPアドレスは自動割り当てされます
サブネットを選択した場合、[接続タイプ]に「SSM」は選択できなくなることに注意してください
ちなみに プライベートサブネット を選択した場合
一部機能が制限されたり、アウトバウンドインターネットを有効にする必要*2が発生します
[作成] を押下します
[AWS Cloud9]コンソール > [自分の環境] > 作成した環境の名前から Cloud9 IDE [開く] を押下します
別ブラウザで Cloud9 統合開発環境(IDE) に遷移します
以降、このCloud9 IDE 画面上で作業を行います
最後に EC2 コンソールに遷移し、作成したCloud9環境の名前で検索してみると
aws-cloud9-
のプリフィクスが付与された名前のEC2インスタンスが起動しているのが確認できます
Cloud9環境が作成できました!
【2】 GitLab/GitHub上のリポジトリをClone, Pullする
GitLab/GihubからリポジトリをClone
したりPull
したりできるようにします
Push
は行いません
0. Gitインストール
Git
はデフォルトでインストールされています
1. SSH鍵の生成
SSH鍵を生成し、パーミッションを設定します
▶︎ SSH鍵を生成。「Ed25519」を使って作成するのがオススメ (クリックで開く)
# SSH鍵を生成。「Ed25519」を使って作成するのがオススメ $ ssh-keygen -t ed25519 Generating public/private ed25519 key pair. Enter file in which to save the key (/home/ec2-user/.ssh/id_ed25519): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/ec2-user/.ssh/id_ed25519. Your public key has been saved in /home/ec2-user/.ssh/id_ed25519.pub. The key fingerprint is: SHA256:E8LjBBny+hoge+\fuga+\hoge+\fuga+\hoge+\fuga+\sample ec2-user@ip-10-99-0-99.ap-northeast-1.compute.internal The key's randomart image is: +--[ED25519 256]--+ | . +oo...+o. | | =.= +.+ .. | | . * X o ... .| | o B = ..o . o.| | . . + S .=. + .| | + o .Eoo. . | | + + ... . | | = o | | o+ . | +----[SHA256]-----+
▶︎ 生成した秘密鍵のパーミッションを適切に設定 (クリックで開く)
# 生成した秘密鍵のパーミッションを適切に設定 $ chmod 400 ~/.ssh/id_ed25519 # 確認 $ ll ~/.ssh total 12 -rw------- 1 ec2-user ec2-user 991 Jul 3 12:03 authorized_keys -r-------- 1 ec2-user ec2-user 464 Jul 3 13:26 id_ed25519 -rw-r--r-- 1 ec2-user ec2-user 137 Jul 3 13:26 id_ed25519.pub
2. 生成した公開鍵をGitLab/GitHubに登録
生成した公開鍵を取得し、GitLab/GitHubに登録することで git clone
や git pull
ができるようにします
▶︎ 生成した公開鍵を取得 (クリックで開く)
# 生成した公開鍵を取得 $ cat ~/.ssh/id_ed25519.pub # => 生成した公開鍵が表示されるのでコピー
GitLabに登録
当該リポジトリ [Settings] > [Repository] > [Deploy Keys]
Push
は行わない予定なので、Grant write permissions to this key
はオフのままにしておきます
GitHubに登録
当該リポジトリ [Settings] > [Deploy Keys] > [Add deploy key]
Push
は行わない予定なので、Allow write access
はオフのままにしておきます
3. リポジトリをClone
$ git clone git@gitlab.com:sample-project/sample-repo # => リポジトリがCloneされる
GitLab/GitHub上のリポジトリをClone
, Pull
することができるようになりました!
【3】 ディスク容量を拡張する
Gitリポジトリに含まれたDockerfileからイメージをビルドする前に、ディスク容量を拡張します
デフォルトで用意されているのは 10GiB ですが、初期状態で空き容量は 3.2GB しかないので、拡張をおすすめします
※無料枠がある場合があるため拡張の上限を先に調べておきましょう
ちなみにこのディスク容量の拡張をやっておかないと、
次章 【4】 Docker, Docker Composeにてコンテナを立ち上げる にて容量不足で失敗することがあります
ディスク容量が不足すると、下記エラーが発生します
No space left on device
0. 現在のディスク容量を確認する
# 現在のディスク容量を確認 $ df -h Filesystem Size Used Avail Use% Mounted on devtmpfs 4.0M 0 4.0M 0% /dev tmpfs 951M 0 951M 0% /dev/shm tmpfs 381M 5.3M 376M 2% /run /dev/nvme0n1p1 10G 6.9G 3.2G 69% / <-- コレ tmpfs 951M 0 951M 0% /tmp /dev/nvme0n1p128 10M 1.3M 8.7M 13% /boot/efi tmpfs 191M 0 191M 0% /run/user/1000
/dev/nvme0n1p1
がユーザが利用できるディスク。既に 69% 使用済み
1. EBSボリュームを拡張する
EBSボリュームの拡張はEC2コンソールにて行います
下記記事がとても詳しいです
Cloud9が容量不足? EBSボリュームを拡張する方法を解説します! | プログラミング入門ナビ by Proglus(プログラス)
ざっくり手順をまとめると下記です
- Cloud9を起動しているEC2インスタンスを停止
- 当該EC2インスタンスにアタッチされているボリュームの容量を変更
- Cloud9を起動しているEC2インスタンスを再起動
※ディスク容量は増やすことしかできないため、慎重にサイズを決めましょう
今回は 20GiB に増やしました
2. ファイルシステムを拡張する
EBSボリュームを拡張しただけではディスク容量は増えません
増やしたいディスクを増やしていきます
公式ドキュメント | ボリュームサイズ変更後の Linux ファイルシステムの拡張 - Amazon Elastic Compute Cloud に沿って作業を進めます
(1) インスタンスが Xen ベースか Nitro ベースかを判断する
Xen インスタンスと Nitro インスタンスでは、デバイスとパーティションの命名が異なることに注意してください。(公式より)
下記コマンドを実行して確認します
$ aws ec2 describe-instance-types --instance-type t3.small --query "InstanceTypes[].Hypervisor" [ "nitro" ]
今回はNitroベースの場合を記述します
Xenベースのケースは、下記記事が詳しいです(再掲)
Cloud9が容量不足? EBSボリュームを拡張する方法を解説します! | プログラミング入門ナビ by Proglus(プログラス)
(2) パーティション拡張
Cloud9環境にはデフォルトでパーティションが存在するため、パーティションを拡張します
▶︎ パーティション拡張 (クリックで開く)
# ボリュームにパーティションがあるかどうかを確認 $ sudo lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS nvme0n1 259:0 0 20G 0 disk ├─nvme0n1p1 259:1 0 10G 0 part / <-- コレ ├─nvme0n1p127 259:2 0 1M 0 part └─nvme0n1p128 259:3 0 10M 0 part /boot/efi # => rootディレクトリの容量を拡張します # => MOUNTPOINTSが "/" のパーティションが、拡張したいパーティション # パーティション拡張 $ sudo growpart /dev/nvme0n1 1 CHANGED: partition=1 start=24576 old: size=20946911 end=20971487 new: size=41918431 end=41943007 # 確認 $ sudo lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS nvme0n1 259:0 0 20G 0 disk ├─nvme0n1p1 259:1 0 20G 0 part / <-- コレ ├─nvme0n1p127 259:2 0 1M 0 part └─nvme0n1p128 259:3 0 10M 0 part /boot/efi # => rootディレクトリがマウントされた "nvme0n1p1" が拡張されていることを確認
(3) ファイルシステム拡張
ファイルシステムを拡張します
▶︎ ファイルシステム拡張 (クリックで開く)
# ファイルシステムの確認 $ df -hT Filesystem Type Size Used Avail Use% Mounted on devtmpfs devtmpfs 4.0M 0 4.0M 0% /dev tmpfs tmpfs 951M 0 951M 0% /dev/shm tmpfs tmpfs 381M 5.3M 376M 2% /run /dev/nvme0n1p1 xfs 10G 6.9G 3.2G 69% / <-- コレ tmpfs tmpfs 951M 0 951M 0% /tmp /dev/nvme0n1p128 vfat 10M 1.3M 8.7M 13% /boot/efi tmpfs tmpfs 191M 0 191M 0% /run/user/1000 # ファイルシステム拡張 $ sudo xfs_growfs -d / meta-data=/dev/nvme0n1p1 isize=512 agcount=3, agsize=1047040 blks = sectsz=4096 attr=2, projid32bit=1 = crc=1 finobt=1, sparse=1, rmapbt=0 = reflink=1 bigtime=1 inobtcount=1 data = bsize=4096 blocks=2618363, imaxpct=25 = sunit=128 swidth=128 blks naming =version 2 bsize=16384 ascii-ci=0, ftype=1 log =internal log bsize=4096 blocks=16384, version=2 = sectsz=4096 sunit=4 blks, lazy-count=1 realtime =none extsz=4096 blocks=0, rtextents=0 data blocks changed from 2618363 to 5239803 # ファイルシステムが拡張されたことを確認 $ df -hT Filesystem Type Size Used Avail Use% Mounted on devtmpfs devtmpfs 4.0M 0 4.0M 0% /dev tmpfs tmpfs 951M 0 951M 0% /dev/shm tmpfs tmpfs 381M 5.3M 376M 2% /run /dev/nvme0n1p1 xfs 20G 6.9G 14G 35% / <-- コレ tmpfs tmpfs 951M 0 951M 0% /tmp /dev/nvme0n1p128 vfat 10M 1.3M 8.7M 13% /boot/efi tmpfs tmpfs 191M 0 191M 0% /run/user/1000
ディスクが拡張できました!
【4】 Docker, Docker Composeにてコンテナを立ち上げる
Docker, Docker Compose環境を構築し、イメージをビルドしてコンテナを立ち上げます
1. Docker インストール, 自動起動の設定
(1) docker
インストール
Amazon Linux 2023
の場合
2023年12月現在、AL2023にはデフォルトで docker-24.0.5
がインストールされてます
インストールされていない場合は下記を参照してください
▶︎ Docker インストール(Amazon Linux 2023) (クリックで開く)
# リポジトリアップデート $ sudo dnf update # docker インストール $ sudo dnf install -y docker
Amazon Linux 2
の場合
▶︎ Docker インストール(Amazon Linux 2) (クリックで開く)
# Amazon Linux Extras を使ってインストール $ sudo amazon-linux-extras install -y docker
# バージョン確認 $ docker -v Docker version 24.0.5, build ced0996
(2) docker
デーモン起動 & 自動起動設定
▶︎ Dockerデーモン起動, および自動起動を設定 (クリックで開く)
# docker デーモン起動 $ sudo systemctl enable --now docker # ステータス確認 $ systemctl status docker ● docker.service - Docker Application Container Engine Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; preset: disabled) Active: active (running) since Mon 2023-12-18 07:39:42 UTC; 11min ago TriggeredBy: ● docker.socket Docs: https://docs.docker.com ...... # => Activeが "active", Loadedが "enabled;" であることを確認 # 自動起動の設定を確認 $ systemctl is-enabled docker enabled # => "enalbed" ならOK
(3) docker
コマンドをsudo
なしで叩けるようにする
▶︎ dockerコマンドをsudoなしで叩けるようにする (クリックで開く)
# dockerグループにec2-userを追加 $ sudo usermod -aG docker ec2-user # dockerグループにec2-userが追加されていることを確認 $ grep docker /etc/group docker:x:990:ec2-user
2. Docker Compose インストール
GitHub docker compose
| リリース履歴 を確認して、適宜バージョンを選択してください
docker
と同じバージョンが無難です
▶︎ Docker Compose インストール (クリックで開く)
# docker-compose インストール $ version=2.24.0 $ DOCKER_CONFIG=${DOCKER_CONFIG:-$HOME/.docker} $ mkdir -p ${DOCKER_CONFIG}/cli-plugins $ curl -SL https://github.com/docker/compose/releases/download/v${version}/docker-compose-linux-x86_64 -o ${DOCKER_CONFIG}/cli-plugins/docker-compose # 実行権限を追加 $ chmod +x ${DOCKER_CONFIG}/cli-plugins/docker-compose
# バージョン確認 $ docker compose -v Docker version 24.0.5, build ced0996
3. Dockerイメージをビルド、コンテナ起動
CloneしたGitリポジトリに遷移し、有効なdocker-compose.yml
が存在することを確認して、下記コマンドを実行します
# イメージをビルド $ docker compose build # コンテナ起動 $ docker compose up -d # コンテナに入る $ docker compose exec app bash
Docker, Docker Compose環境の構築、およびイメージのビルドが完了しました!
【5】 デプロイ先のEC2インスタンスへのSSH通信を設定する
異なるVPC上に存在するEC2インスタンスへのSSH通信ができるようにします
1. ElasticIP(EIP)を作成
EC2 コンソールを開き、[インスタンス] 画面にてCloud9インスタンスを選択し、「パブリックIPv4アドレス
」が設定されていることを確認します
※割り当てられていない場合、Cloud9インスタンスがパブリックサブネット上に配置されていることを確認してください
左ペインから [ネットワーク&セキュリティ] > [ElasticIP] 画面に遷移します
[Elastic IP アドレスを割り当てる] を選択します
[割り当て] 押下します
EIPが作成されたことを確認します
2. 作成したEIPをCloud9インスタンスにアタッチ
[ElasticIP] 画面にて
作成したEIPを選択し、 [アクション] > [Elastic IP アドレスの関連付け] を押下します
Cloud9インスタンス、プライベートIPアドレスを選択します
[関連づけられたインスタンス]列にCloud9インスタンスが表示されることを確認します
3. 作成したEIPを、接続先のセキュリティグループのインバウンドに追加
EC2 コンソール > [インスタンス] 画面にて、接続先のEC2インスタンスを選択し、[セキュリティ] タブ内 [セキュリティグループ] を押下します
[セキュリティグループ詳細画面]にて、[インバウンドのルールを編集] を押下します
左下にある [ルールを追加] を押下し、下記を設定して、[ルールを保存] を押下します
- タイプ: SSH
- ソース: 作成したEIP /32
- 説明: (説明を記載)
4. 対象のEC2インスタンスにSSH接続できることを確認
- 対象EC2インスタンスのプライベートキーファイル*3 をローカルに保存
- ローカルに保存したプライベートキーファイルをCloud9にアップロード
ローカルのエクスプローラを開き、ドラッグ&ドロップでアップロードできます
パーミッションを変更します
$ chmod 400 <アップロードしたプライベートキーファイル>
- 接続確認
$ ssh ec2-user@<当該EC2のパブリックIPアドレス> -i <アップロードしたプライベートキーファイル>
接続できたら完了!
アップロードしたプライベートキーファイルは ~/.ssh
配下に移動しておくと無難です
【6】 作成したCloud9環境を複数のユーザに共有する
環境が作成できたので、他のユーザに共有します
弊社ではAWS Single Sign-On (AWS SSO)が導入されています
今回この環境を共有したいのは、AWSCloud9Administrator
権限を持つフェデレーションユーザ(フェデレーティッドユーザ)です
公式ドキュメント | AWS Cloud9 で共有環境を使用する - AWS Cloud9を参考に、ユーザを招待していきます
1. フェデレーションユーザのARNを生成
公式ドキュメントによると、フェデレーションユーザを招待するには下記ARNの生成が必要です
arn:aws:sts::123456789012:assumed-role/MyAssumedRole/MyAssumedRoleSession
123456789012
を AWS アカウント ID に、MyAssumedRole
を引き受けたロールの名前に置き換えます。
MyAssumedRoleSession
を引き受けたロールのセッション名に置き換えます。
AWSアカウントID、および MyAssumedRole/MyAssumedRoleSession
は、AWSマネジメントコンソールの右上、アカウントメニューのプルダウンから確認できます
確認したAWSアカウントID、フェデレーティッドユーザを元にARNを生成します
2. 権限追加
- Cloud9 IDE 右上にある [share]押下
[Invite Members] のボックスにフェデレーションユーザのARNを入力、権限は「
RW
」を指定して[Invite]押下下記WARNINGが表示されるので[OK]押下
登録完了
登録した権限を確認します
3. URL共有
環境を作成したユーザ以外のユーザは、AWSマネジメントコンソール経由ではなく、共有用URLからのアクセスになります
URLは、[Share]押下で表示されるモーダルからコピーできます
作成したCloud9環境を複数のユーザに共有しました!
おまけ: 【7】 Cloud9環境からAWSサービスへのアクセスを制限する
Cloud9には、 AWSマネージド一時認証情報(AWS Managed Temporary Credentials: AMTC) という認証サービスがあります
公式ドキュメント | AWS Cloud9 での Identity and Access Management - AWS Cloud9
AWSサービスへのアクセス時に利用できる一時認証情報で、Cloud9を起動するたびに、~/.aws/credentials
に認証情報を自動生成・更新してくれます
この認証では、(ごく一部を除き)すべてのAWSリソースのすべてのAWSアクションに許可が与えられます
Cloud9 IDEを起動するたびに下記モーダルが表示される場合、この認証サービスが有効になっています
Force update
を押下すると、~/.aws/credentials
が強制的に上書きされてしまいます
この広すぎる権限を抑制する方法を記述します
1. IAMロールをアタッチする
適切な権限を付与したIAMロールをCloud9インスタンスにアタッチすることで、権限を抑制することができます
詳細は、松井さんが書いた下記の記事を参考にしてください(再掲)
2. AWS Managed Temporary Credentials をオフにする
※この手順は、Cloud9環境作成者のみが実行できます
Cloud9 IDE にて、左上の雲マーク > [Preferences] を押下
[AWS Settings] を押下
[AWS management temporary credentials
]がONであることを確認[
AWS management temporary credentials
]をOFFにする
3. ~/.aws/credentials
削除
AWS認証には優先順位があり、~/.aws/credentials
はIAMロールより優先して参照されてしまいます
公式ドキュメント | 認証とアクセス認証情報 - AWS Command Line Interface
邪魔な ~/.aws/credentials
を削除します
$ rm ~/.aws/credentials
以上で、AWSサービスへのアクセス時にAMTCではなく、IAMロールを参照するようになります
下記記事も大変参考にさせていただきました
AWS Cloud9環境で利用できる一時クレデンシャル『AWS Managed Temporary Credentials』について調べてみた | DevelopersIO
まとめ
Cloud9上に共有環境を構築したことで、個別のネットワーク環境はマシン環境に依存することなく、安定的にアプリケーションをデプロイすることができるようになりました
Cloud9上に基礎的な環境を構築する手段を知っておくことで、ペアプロ環境や検証環境などの構築が気軽に行えるようになります
ぜひ試してみてください
ここまでお読みいただいてありがとうございました
*1:VPC, パブリックサブネット, セキュリティグループ