この記事について
「ローカル環境を汚さずにいろんなツールを入れて試して勉強・アプリを開発してみたい!」「本番環境にアプリをのせるときに、サーバーに直接接続して作業するのではなくて、イケてるデプロイフローを構築して使いたい!」と思う"目指せ初心者脱却マン"は多いと思います。
今回は、開発環境のコンテナ化+AWS Elastic BeanstalkとCircle CIを使った自動デプロイフローを構築するまでの一連の流れを紹介したいと思います。いろんな記事・本を行ったり来たりしないでこの記事だけで完結させることを目標にします。
使用する環境・バージョン
開発環境
- OS : macOS Mojave 10.14.5
- git : 2.20.1 (Apple Git-117)
- EB CLI 3.15.3 (Python 3.7.4)
- docker : 19.03.8, build afacb8b
- Docker.app : 2.2.0.5
- VS Code : 1.44.2
- VS Code Remote Development : 0.20.0
アプリ
- Node.js : v12.13.0
- npm : 6.13.4
- express : 4.17.1
- mongoose : 5.9.11
前提条件
- 以下のことがすでに行われている・インストール済みであることとします。
- VS Codeと拡張機能 Remote Development
- Docker
- AWSのアカウント
- EB CLI
- Githubのアカウント
- Circle CIへのGithub連携サインアップ
- ローカルアプリのソースコードは一応載せますが、そのコードについて事細かに解説するのは記事の主旨から外れるので今回はなしです。
読者に要求する前提知識
- 基本的なターミナルコマンドが扱えること
- gitが問題なく扱えること
- コンテナ(Docker)という概念と関連用語・コマンドについて知っていること
- イメージ・ボリューム・ネットワークやコマンドについては今回深く解説しません。
- TCP/IP等の基本的なネットワークの知識
- 「何番ポートを開ける」という言葉がわかれば最低限OKです
作業工程
0. アーキテクチャ・ディレクトリ構造
目指すローカル+本番環境は以下の通りです。
また、ローカル環境での最終的なディレクトリ構造は以下のようになります。
/app #アプリのルートディレクトリ
├─.circieci # CircleCIの設定ファイルを格納
│ └─config.yml
├─.devcontainer # VSCodeRemoteContainerの設定ファイルを格納
│ ├─devcontainer.json
│ └─docker-compose.yml
├─.elasticbeanstalk # ElasticBeanstalkの設定ファイルを格納
│ └─config.yml
├─.ebextensions # ElasticBeanstalkのオプション設定ファイルを格納
│ └─env.config
├─.gitignore
├─Dockerfile
├─docker-compose.yml
├─.dockerignore
├─node_modules
│ └─(略)
├─package.json
├─package-lock.json
└─src # アプリのソースコード
├─controllers
│ └─personsController.js
├─models
│ └─person.js
└─main.js
1. ローカルアプリのソースコードを作成
アプリの初期化
アプリのルートディレクトリで以下のコマンドを実行します。
$ npm init -y
$ npm i express -S
$ npm i mongoose -S
そうしたら、作成されたpackage.json
を以下のように書き換えます。
{
(略)
"main": "src/main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node src/main"
},
(略)
}
アプリのソースコード作成
今回は環境構築がメインなので、アプリ自体は「ルートにアクセスしたら、mongoDBに格納されている全ての情報をjsonで返す」という簡単なものにします。
以下コードです。
"use strict";
const express = require("express");
const app = express();
const personsController = require("./controllers/personsController");
const mongoose = require("mongoose");
mongoose.connect(
"mongodb://mongo-db:27017/testdb",
{useNewUrlParser: true}
);
const db = mongoose.connection;
db.once("open", () => {
console.log("successfully connected to mongoDB");
})
app.set('port', 3000);
app.get("/", personsController.getAllPersons, (req, res, next) => {
console.log("server get request on root");
res.send(req.data);
});
app.listen(app.get('port'), () => {
console.log(`The Express.js server has started and is listening on port number: ${app.get('port')}`);
});
"use strict";
const mongoose = require("mongoose");
const personSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true,
lowercase: true,
unique: true
},
zipCode: {
type: Number,
min: [10000, "Zip code too short"],
max: 99999
},
});
module.exports = mongoose.model("Person", personSchema);
"use strict";
const Person = require("../models/person");
exports.getAllPersons = (req, res, next) => {
Person.find({}, (error, persons) => {
if (error) next(error);
req.data = persons;
next();
});
};
2. gitの準備をする
アプリのルートディレクトリで以下のコマンドを実行して、gitの初期化と.gitignore
ファイルの作成を行います。
$ git init
$ touch .gitignore
.gitignore
ファイルに以下のように記述して、これらのファイルをgitの管理対象外にします。
node_modules/
.gitignore
3. アプリケーションレイヤーのDocker化
「Docker化=作ったアプリをdockerのイメージにする」ということです。
ここではNode.jsで動くアプリケーションレイヤーの方のDocker化をまず先に行います。
Dockerfile
の作成
Dockerイメージの詳細はDockerfile
に記述されます。アプリのルートディレクトリにDockerfile
を作成し、以下のように記述します。
FROM node:12
WORKDIR /app
COPY package.json .
COPY package-lock.json .
RUN npm install
COPY . .
EXPOSE 3000
CMD [ "node", "src/main.js" ]
参考:How To Deploy a Node App on AWS Elastic Beanstalk with Docker
参考:Node.js公式ドキュメント Node.js Web アプリケーションを Docker 化する
記述した設定の意味は以下の通り。
-
FROM node:12
→ node.js ver12の公式コンテナイメージを元にする。 -
WORKDIR /app
→ 以下の作業はコンテナ内のappディレクトリで行う。 -
COPY ~
→ ローカルのpackage.json
とpackage-lock.json
ファイルをコンテナ内のカレントディレクトリにコピー -
RUN npm install
→ コンテナ内のカレントディレクトリでnpm installを実行 -
COPY . .
→ ローカルの残りのファイルをコンテナ内のカレントディレクトリにコピー -
EXPOSE 3000
→ コンテナの3000番ポートを開ける -
CMD ~
→ コンテナ起動時にnode src/main.js
を実行
Dockerfile
に記述できるコードについては以下で詳しく説明されています。
参考:Dockerfileの書き方と使い方
参考:Dockerfile リファレンス
.dockerignore
の作成
Dockerfile
の設定により「ローカルディレクトリ内の全てのファイルをコンテナ内にコピーする」という動作が行われますが、node_modules
のようなコピーしてたら重くてしょうがないものを対象外にします。
そもそもnodeのモジュールはnpm installで取得する仕様にしたのでわざわざローカルからコピーしなくても問題ないのです。
アプリのルートディレクトリ上に.dockerignore
を作成して以下のように記述します。
node_modules
npm-debug.log
参考:シンプルなNodeアプリをDocker化してElastic Beanstalkに移行してみた
4. mongoDB用のコンテナを作成し、アプリケーションレイヤーコンテナと連携させる
docker-compose.yml
の作成
複数個のDockerコンテナを連携させるためには、そのための設定をdocker-compose.yml
に記述します。
アプリのルートディレクトリにdocker-compose.yml
を作成して以下のように編集します。
# docker-compose記法のバージョン
version: '3.3'
# 起動するコンテナの種類を定義
services:
#以下node.jsのアプリケーションレイヤーの設定。このコンテナには「node-web」と名前がつく
node-web:
# build時にカレントディレクトリにあるDockerfileのイメージを使用する
build: .
ports:
# localの8888番ポートと、コンテナの3000番ポートをつなげる
- "8888:3000"
# コンテナ内でのホスト名
hostname: web-server
# このコンテナは、以下記述する「mongo-db」コンテナが立ち上がってから作成される。
depends_on:
- mongo-db
# 以下mongoDBのコンテナ設定。コンテナ名は「mongo-db」とつく。
mongo-db:
# mongo:3.6の公式コンテナイメージを元にして作成する。
image: "mongo:3.6"
ports:
- "27017:27017"
hostname: db-server
volumes:
#コンテナ内の/data/dbの中身を、「db-volume」という名前のvolumeにマウント
- db-volume:/data/db
- db-config-volume:/data/configdb
# 作成するvolumeの名前を列挙
volumes:
db-volume:
db-config-volume:
参考:dockerでnodejs, mongodbのローカル開発環境を構築してVisual Studio Codeでデバッグする
参考:さわって理解するDocker入門第4回 Docker Composeを使った複数コンテナのデプロイ
参考:Docker入門 〜Docker-compose, ネットワーク, ボリューム編〜
一般的にdocker-compose.yml
に記述できるキーについての説明は以下がわかりやすいです。
参考:docker-compose の設定マニュアル最新版を日本語で!!
5. VS Code のRemote Developmentを使ってDockerに乗ったリモート開発環境を作る
開発環境をコンテナ化することで、ローカル環境を汚さなくて済んだり、環境構築に失敗した時の後片付けが簡単だったり(そのコンテナを廃棄すればいいだけ)、開発メンバー間で環境がシェアできたりと何かと便利です。
参考:開発環境をDockerに乗せる方法とメリットを3ステップで学ぶチュートリアル
そのため、ローカルでの環境もDocker化して、そのコンテナにVS CodeのRemote Developmentという拡張機能を用いて入る方法で開発を進めます。
VS Codeでのコンテナへの接続方法
まず、VS Codeの画面左下にある緑色の「><」ボタンを押します。
画像出典:VS Code 公式ドキュメント Developing inside a Container
開いたコマンドパレットの中から「Remote-Containers: Open Folder in Container…」を選択して、アプリのルートディレクトリをRemote ContainerとしてOpenすると選択します。
その後、コマンドパレットに「How would you like to create your container configuration?」と表示されるので、「From 'docker-compose.yml'」を選択します。こうすることで、docker-compose.yml
に書いた設定通りに開発環境が作られます。
選択した後、コマンドパレットに「Select a service」と表示されます。コードをいじるために入って開発したいのはアプリケーションレイヤー側なので、ここではnode-webを選択します。
すると、コンテナが自動で作成され、中身をVS Codeで編集できるようになります。
接続した後の状況
接続時のアーキテクチャは以下の図の通りです。
画像出典:VS Code 公式ドキュメント Developing inside a Container
この状態では、Dockerコンテナ上のファイルを直接編集が可能になり、DockerホストとDockerコンテナの間でソースコードを同期する必要がなくなります。
ファイル新規作成/削除・ファイル編集・git操作・npm install
まで全て同期されます。
参考:Visual Studio CodeのRemote DevelopmentとDockerで快適な開発環境をゲット
作成される環境は、docker-compose up
を実行したときと全く同じです。
アプリケーションレイヤーのnode-webコンテナとDBレイヤーのmongo-dbコンテナ、volumeが2つ(db-volumeとdb-config-volume)、ネットワークが1つ(app_defaultという名前)作られます。
これらはdocker-compose.yml
で設定した通り、
- mongoDBコンテナにドメイン名
mongo-db
でアクセス可能(ping mongo-db
で確認できる) - ホストマシンの8888番ポートとアプリ側コンテナの3000番ポートが繋げてある
- mongoDBの内容は2つのvolumeに入る
という状態なので、コンテナ内でnpm start
すれば、ローカルマシンの方でwebブラウザを開き、http://localhost:8888
にアクセスすることでアプリの挙動が確認できます。また、ボリュームもマウントされているので、コンテナを一旦停止したとしてもDBの内容は失われません。
参考:VS Code / Remote - Containers で docker-compose を試す
参考:Dockerize a Node.js app connected to MongoDb
VS Code Remote Developmentの設定ファイル
このVS Codeの設定が.devcontainer/devcontainer.json
と.devcontainer/docker-compose.yml
のファイルの形で保存されます。このファイルは最初に環境を作って接続するときに自動作成されます。
// For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file's README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.112.0/containers/docker-existing-docker-compose
// If you want to run as a non-root user in the container, see .devcontainer/docker-compose.yml.
{
"name": "Existing Docker Compose (Extend)",
"dockerComposeFile": [
"../docker-compose.yml",
"docker-compose.yml"
],
"service": "node-web",
"workspaceFolder": "/workspace",
"settings": {
"terminal.integrated.shell.linux": null
},
"extensions": []
}
version: '3.3'
services:
node-web:
volumes:
- .:/workspace:cached
command: /bin/sh -c "while sleep 1000; do :; done"
設定ファイルをgit管理対象から外す
設定ファイル.devcontainerはgit管理対象外にする方がいいそうです。
参考:VSCode Remote Containerが良い
なので、.gitignore
に以下の一文を追記します。
.devcontainer/
(おまけ)mongoDBと接続しないNode.js単独コンテナの場合
開発環境で使うコンテナが1つだけの場合は、docker-compose.yml
ではなくてDockerfile
を元にして接続することができます。
「><」ボタン→「Remote-Containers: Open Folder in Container…」までは上記の手順と同じで、次に「From 'Dockerfile'」を選択すれば、単独コンテナの開発環境を構築→VS Codeで接続することができます。
この時、docker-compose.yml
のときとはまた別の、単独コンテナ用の.devcontainer/devcontainer.json
設定ファイルが作られます。内容は以下の通り。
{
"name": "Existing Dockerfile",
"context": "..",
"dockerFile": "../Dockerfile",
"settings": {
"terminal.integrated.shell.linux": null
},
"extensions": []
}
このコンテナの起動直後は、ローカル端末とコンテナーはネットワーク上隔離されているので、コンテナー内のポートへ直接接続ができません。もしもこの中で動かしているアプリの挙動をhttp://localhost:XXXX
で確認したいというならば、コンテナのYYYY番ポートとローカルのXXXX番ポートをつなげる設定を.devcontainer/devcontainer.json
に追加する必要があります。
// local: port XXXX, container: port YYYY
"appPort": ["XXXX:YYYY"]
追加した設定を反映させるには、コンテナをrebuildさせる必要があります(restartではダメ)。
コマンドパレットに「>Remote-Containers: Rebuild Container」と入力して実行すれば、新しい設定に合わせて自動でコンテナが作り直されます。
参考:VS CodeのRemote-Containersでリモートサーバー上のコンテナーの開発を行う方法
6. 本番環境用のmongoDBサーバーを立ち上げる
今回本番環境へアプリをデプロイするのにElastic Beanstalkを使いますが、このElastic Beanstalkというサービスはステートレスなアプリのデプロイをサポートしているもので、mongoDBのようなステートフルのものをこれでやろうとするのはベストプラクティスではないようです。
参考:Running mongodb with Elastic Beanstalk
参考:【初心者向け】ステートフル(Stateful)とステートレス(Stateless)の違い,IPv6やAWSでの考え方
ですので、mongoDBのサーバーはElastic Beanstalkとは別に立てて、あとからアプリサーバーと連携させる形をとります。
EC2インスタンスを作成
AWS EC2の詳しい操作については今回は割愛します。
今回はAmazon Linux2のOSを選びました。
SSH接続用の22番ポートと、mongoDB用の27017番ポートを空けてインスタンスを作成します。
mongoDBのインストール
作成したEC2インスタンスにSSH接続します。
$ ssh ec2-user@<サーバードメイン> -i <path to key>
__| __|_ )
_| ( / Amazon Linux 2 AMI
___|\___|___|
謎の図形と「Amazon Linux 2 AMI」という文字が表示されれば接続成功です。
接続したら、/etc/yum.repos.d/mongodb.repo
を開いて以下のように書き込みます。
$ sudo vim /etc/yum.repos.d/mongodb.repo
# 以下を書き込んで保存
[mongodb-org-3.2]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/amazon/2013.03/mongodb-org/3.2/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-3.2.asc
その後、以下のコマンドを打ってmongoDBをインストールします。
$ sudo yum install -y mongodb-org
sudo service mongod start
やsudo service mongod stop
といった、起動・停止コマンドが効けばインストール成功です。
参考:MongoDB On EC2を試してみる
その後、localhost以外からのアクセスを受け付けるように、configファイルを以下のように編集します。
$ sudo vim /etc/mongod.conf
# 以下をコメントアウト
# bind_ip=127.0.0.1
参考:AWSでmongoを動かしてみる(AutoScale対応)
そうしたら、sudo service mongod start
でmongoDBを起動させてからサーバーログアウトします。
7. 本番環境用の設定をアプリに反映させる
今のローカルアプリのコードでは、アプリケーションレイヤーは3000番ポートで通信・DBはローカルで作成したコンテナに接続するようになっています。このままだと本番環境に乗せても動きません。
なので、「本番環境を示す環境変数が存在する場合は本番用の設定を参照、そうでないならローカル用の設定を参照」とするようにします
/*
mongoose.connect(
mongodb://mongo-db:27017/testdb,
{useNewUrlParser: true}
);
*/
const mongoDB = process.env.NODE_ENV === "production" ? 'mongodb://[mongoDBをインストールしたインスタンスのIP address]:27017/testdb' : 'mongodb://mongo-db:27017/testdb';
mongoose.connect(
mongoDB,
{useNewUrlParser: true}
);
// app.set('port', 3000);の部分を以下のように修正
app.set('port', process.env.PORT || 3000);
これで、
- NODE_ENVという環境変数の値が"production"ならば本番DBサーバーを参照、そうでないならローカルコンテナのDB
- アプリの通信用PORT番号が定められているならその値を、そうでないなら3000番ポートを開く
という設定になりました。
8. Elastic Beanstalkの設定
Elastic Beanstalkのサービス自体の説明は、以下のAWSのスライドでわかりやすく説明されています。
参考:[AWSマイスターシリーズ] AWS Elastic Beanstalk
今回は、コマンドラインからアプリのデプロイができるように設定していきます。
EB CLIのインストール
以下の公式ドキュメントにやり方が詳しく書かれています。インストールしていない人は入れましょう。
参考:AWS公式ドキュメント macOS で EB CLI をインストールします。
EB CLIのためのアクセスキーを取得する
CLIでコマンドを打ったときに、どのアカウントが使われるのかを設定する必要があります。
このアカウント紐付けに使われるのがアクセスキーです。
アクセスキーを取得していない人は、以下の記事を参考にして、AWSのウェブコンソールから取得してください。
参考:AWS CLIのインストールから初期設定メモ
アクセスキーを取得したら、Elastic Beanstalkの機能をフルで使えるように、「AWSElasticBeanstalkFullAccess」の権限をキーに付けます。
参考:【AWS】Elastic BeanstalkでDjangoアプリをデプロイしてみた
参考:Elastic Beanstalkトラブルシューティング集
eb init
でElastic Beanstalkの初期化を行う
eb init
のコマンドを叩くことによって、デプロイのための最低限の設定ファイルが作られます。
アプリのルートディレクトリ下で実行します。
$ eb init
# どこのリージョンにアプリをデプロイするか選択
Select a default region
1) us-east-1 : US East (N. Virginia)
2) us-west-1 : US West (N. California)
3) us-west-2 : US West (Oregon)
(略)
9) ap-northeast-1 : Asia Pacific (Tokyo)
(略)
(default is 3): 9
# 初めてCLIを使う場合で、アクセスキーとCLIが紐づいていない場合はここで聞かれます。
# 一度でもこれを入力したことがある場合はこの項目はスキップされます。
You have not yet set up your credentials or your credentials are incorrect.
You must provide your credentials.
(aws-access-id): your-access-key-id
(aws-secret-key): your-access-secret-key
# 入力したら、~/.aws/configファイルの中に設定が保存されて、以降はそれが参照されます。
# アプリの名前を決める
Enter Application Name
(default is "app"):
Application app has been created.
# Dockerfileがディレクトリ内にあったことから、Dockerアプリだと自動で判断してくれた。
# あっているのでYを入力
It appears you are using Docker. Is this correct?
(Y/n): Y
# 使うDockerの種類を選択
Select a platform version.
1) Docker 18.09.9-ce
2) Docker
(default is 1):
# アプリのコードの置き場所としてCodeCommitを使うかどうか。
# Noを選択すると、S3のバケットが自動で用意されてそこに格納されるようになる。
Do you wish to continue with CodeCommit? (y/N) (default is n): n
# アプリがデプロイされるインスタンスにSSH接続できるようにするかの設定
# SSH接続できれば、何かあったときにサーバー内に入って調べられるようになるのでYが無難
Do you want to set up SSH for your instances?
(Y/n): Y
# SSH接続するためのキーペアを何にするかを選択
Select a keypair.
1) your-keypair
2) [ Create new KeyPair ]
(default is 1): 1
参考:Elastic Beanstalk にEB CLIから簡単デプロイ
参考:AWS CLIのプロファイルを切り替えてebコマンドで既存ElasticBeanstalk Applicationにアクセスする
すると、アプリルートディレクトリ下に.elasticbeanstalk/config.yml
が以下のように作成されて、設定が保存されます。
branch-defaults:
master:
environment: null
group_suffix: null
global:
application_name: app
branch: null
default_ec2_keyname: my-keyname
default_platform: Docker
default_region: ap-northeast-1
include_git_submodules: true
instance_profile: null
platform_name: null
platform_version: null
profile: eb-cli
repository: null
sc: git
workspace_type: Application
また、AWSのコンソールでElastic Beanstalkのページを確認すると、きちんとappというアプリができている。この時点でこのアプリに環境はまだ存在しません。
オプション設定を追加
7章で、本番環境ではNODE_ENVという環境変数を設定する仕様にしたので、デプロイしたコンテナにNODE_ENV=productionという値を渡すようにオプション設定をします。
凝った環境のカスタマイズをするためには、アプリのルートディレクトリに.ebextensions
というファイルを用意して、その中に設定ファイルを作ります(ここではenv.config
とします)。
環境変数設定のためには以下のように記述します。
option_settings:
- option_name: NODE_ENV
value: production
参考:AWS公式ドキュメント 設定ファイル (.ebextensions) による高度な環境のカスタマイズ
参考:AWS Elastic Beanstalkで環境変数を追加する
Elastic Beanstalkの環境を作成する
Elastic Beanstalkでは、一つのアプリに対して本番環境や検証環境、開発環境など複数個の環境が作られることを想定しているので、アプリ1つに対して複数個環境という関係になっています。
参考:ebコマンドを使ってElasticBeanstalkでデプロイしてみる
gitのブランチ一つに対して一つの環境が紐づくようになっているので、まずは今のコードを全てコミットしておきます。
$ git commit -m "first commit"
そこで、環境を作成→デプロイするためのeb create
コマンドをルートディレクトリ上で実行します。
$ eb create
Enter Environment Name
(default is app-dev):
Enter DNS CNAME prefix
(default is app-dev):
Select a load balancer type
1) classic
2) application
3) network
(default is 2):
設定の入力が終わったら、起動ログがターミナルに流れます。
Creating application version archive "your-app-deployed-version".
Uploading [your-app-file].zip to S3. This may take a while.
Upload Complete.
Environment details for: app-dev
Application name: app
Region: ap-northeast-1
Deployed Version: your-app-deployed-version
Environment ID: xxxxxxxxxxx
Platform: arn:aws:elasticbeanstalk:ap-northeast-1::platform/Docker running on 64bit Amazon Linux 2/0.1.0
Tier: WebServer-Standard-1.0
CNAME: app-dev.ap-northeast-1.elasticbeanstalk.com
Updated: yyyy-mm-dd hh:mm:ss
Printing Status:
yyyy-mm-dd hh:mm:ss INFO createEnvironment is starting.
yyyy-mm-dd hh:mm:ss INFO Using elasticbeanstalk-ap-northeast-1-[your bucket ID] as Amazon S3 storage bucket for environment data.
yyyy-mm-dd hh:mm:ss INFO Created target group named: [your-target-group-name]
yyyy-mm-dd hh:mm:ss INFO Created security group named: [your-security-group-name]
yyyy-mm-dd hh:mm:ss INFO Created security group named: [your-security-group-name-2]
yyyy-mm-dd hh:mm:ss INFO Created Auto Scaling launch configuration named: [your-configuration-name]
yyyy-mm-dd hh:mm:ss INFO Created Auto Scaling group named: [your-auto-scaling-group-name]
yyyy-mm-dd hh:mm:ss INFO Waiting for EC2 instances to launch. This may take a few minutes.
yyyy-mm-dd hh:mm:ss INFO Created Auto Scaling group policy named: [yout-auto-scaling-policy-name]
yyyy-mm-dd hh:mm:ss INFO Created Auto Scaling group policy named: [yout-auto-scaling-policy-name-2]
yyyy-mm-dd hh:mm:ss INFO Created CloudWatch alarm named: [your-cloudwatch-alarm-name]
yyyy-mm-dd hh:mm:ss INFO Created CloudWatch alarm named: [your-cloudwatch-alarm-name-2]
yyyy-mm-dd hh:mm:ss INFO Created load balancer named: [your-load-balancer-name]
yyyy-mm-dd hh:mm:ss INFO Created Load Balancer listener named: [your-load-balancer-listener-name]
yyyy-mm-dd hh:mm:ss INFO Successfully pulled node:12
yyyy-mm-dd hh:mm:ss INFO Successfully built aws_beanstalk/staging-app
yyyy-mm-dd hh:mm:ss INFO Docker container [docker-ID] is running aws_beanstalk/current-app.
これでアプリのデプロイに成功しました。
EB CLIで実行できる操作
eb status
で環境の状態ステータス(OK, severe, pendingなど)が確認できます。
$ eb status
Environment details for: app-env
Application name: app
Region: ap-northeast-1
Deployed Version: your-app-deployed-version
Environment ID: xxxxxxxxxxx
Platform: arn:aws:elasticbeanstalk:ap-northeast-1::platform/Docker running on 64bit Amazon Linux 2/0.1.0
Tier: WebServer-Standard-1.0
CNAME: app-dev.ap-northeast-1.elasticbeanstalk.com
Updated: yyyy-mm-dd hh:mm:ss
Status: Ready
Health: Green
eb open
で作った環境のURLをブラウザで開くことができます。
eb deploy
で修正デプロイを行うことができます。
例えば、今の環境に紐づいているブランチにコミットを付け足して、その状態でこのコマンドを叩くと、修正デプロイ実行の様子がログで表示されます。
$ git commit -m "bug fix"
$ eb deploy
Creating application version archive "your-app-deployed-version".
Uploading [your-fixed-app-file] to S3. This may take a while.
Upload Complete.
yyyy-mm-dd hh:mm:ss INFO Environment update is starting.
yyyy-mm-dd hh:mm:ss INFO Deploying new version to instance(s).
yyyy-mm-dd hh:mm:ss INFO Successfully pulled node:12
yyyy-mm-dd hh:mm:ss INFO Successfully built aws_beanstalk/staging-app
yyyy-mm-dd hh:mm:ss INFO Docker container [docker ID] is running aws_beanstalk/current-app.
yyyy-mm-dd hh:mm:ss INFO New application version was deployed to running EC2 instances.
yyyy-mm-dd hh:mm:ss INFO Environment update completed successfully.
eb terminate --all
で、Elastic Beanstalkの環境・アプリもろとも全て破棄することができます。ローカルに自動生成された.elasticbeanstalk
フォルダも自動でなくなります。
$ eb terminate --all
The application "app" and all its resources will be deleted.
This application currently has the following:
Running environments: xxx
Configuration templates: xx
Application versions: xxx
To confirm, type the application name: app
Removing application versions from s3.
yyyy-mm-dd hh:mm:ss INFO deleteApplication is starting.
yyyy-mm-dd hh:mm:ss INFO Invoking Environment Termination workflows.
yyyy-mm-dd hh:mm:ss INFO The environment termination step is done.
yyyy-mm-dd hh:mm:ss INFO The application has been deleted successfully.
参考:AWS公式ドキュメント EB CLI による Elastic Beanstalk 環境の管理
参考:AWS公式ドキュメント Express アプリケーションを Elastic Beanstalk にデプロイする
参考:5分でAWS Elastic Beanstalk(作って、修正して、お片付け)
9. Circle CI の導入
最後にCircle CIを使って、Githubにpushしただけで自動デプロイができるようにします。
Circle CIが使うアクセスキーを取得
8章で作ったものとは別に、Circle CIに渡す専用のアクセスキーを作成します。これにも「AWSElasticBeanstalkFullAccess」の権限を付与します。
Elastic Beanstalkの設定ファイルをgit管理対象に含める
Githubにプッシュした内容を見てCircle CIがデプロイ操作をするので、Elastic Beanstalkの設定はGithub上にのせる必要があります。
デフォルトでは管理外になっているので、.gitignore
に以下の追記をして管理対象に含めます。
!.elasticbeanstalk/config.yml
参考:CircleCI経由でElasticBeanstalkにデプロイする方法
Circle CIの設定ファイルを作る
設定はアプリのルートディレクトリの.circieci/config.yml
に書くことになっています。
なので、ファイルを作成して以下のように記述します。
# circleciのバージョン
version: 2
# jobの設定
jobs:
# deployという名前のjobの定義を以下記述
deploy:
# circleciが検証用に用意するコンテナ内でのソースコードの置き場
working_directory: ~/app
# circleciが建てるdocker imageの種類
docker:
- image: circleci/node:12
# deployというjobを行うためにcircleciのdocker内で動作させるコマンド
steps:
- checkout
- run: npm install
- save_cache:
paths:
- node_modules
key: v1-dependencies-{{ checksum "package.json" }}
- run:
name: Installing EB CLI
working_directory: /
command: |
sudo apt-get -y -qq update
sudo apt-get install python-pip python-dev build-essential
sudo pip install awsebcli --upgrade
- run:
name: Deploying
command: eb deploy [created-my-env-name]
# workflow(jobを順番どうりに実行する一連のフロー)の定義
workflows:
version: 2
# workflowの名前をbuildとする
build:
# build workflowで実行するjobの順番
jobs:
- deploy:
# deploy jobを行うのは、Githubのmasterブランチにpushが行われたときのみ
filters:
branches:
only:
- master
参考:How to deploy your NodeJs app on Amazon Elastic Beanstalk (AWS EB) with CircleCI — Short Tutorial
設定ファイルに書くことのできるキーの意味については以下の記事がわかりやすい。
参考:いまさらだけどCircleCIに入門したので分かりやすくまとめてみた
Githubのリモートリポジトリにpush
Githubのページから新しいリポジトリを作り、ローカルリポジトリと連携させます。
$ git remote add origin <git url>
$ git push -u origin master
Circle CIのプロジェクト作成
Circle CIのページで、先ほど作ったGithubのリモートリポジトリを選択して「set up project」のボタンを押す。
すると、configファイルをどうするかを設定する画面に遷移します。先ほど手動で作ってもうすでにリポジトリ内に存在するので、「add manually」を選択します。
そうすると、projectのページに自動遷移して、ビルドの様子を監視できるようになります。
Circle CIにEB CLIのアクセスキーを渡す
ただ、このままだとCircle CIはAWSにアクセスする権限がないので、デプロイは失敗します。
そのため、先ほど作ったCircle CI用のアクセスキーの情報を環境変数にして渡します。
project settingsを開いて、その中の「Environment Variables」というタブを選択します。
そこで、以下の環境変数を追加します。
- AWS_ACCESS_KEY_ID: [your-access-key]
- AWS_SECRET_ACCESS_KEY: [your-secret-access-key]
もう一度アプリをpush
ソースコードのどこかを適当に変えて(挙動に影響が出ない程度に)、Githubのmasterブランチに再びpushします。
すると、pushを感知してCircle CIが動き、アプリのデプロイができます。
もしデプロイ時に「InvalidProfileError」が出るなら、.elasticbeanstalk.config.yml
の設定ファイルのprofile: eb-cli
をコメントアウトすれば一応動くようにはなります。
参考:How to setup Elastic Beanstalk Deployment?
まとめ
これでとりあえず最低限の環境構築ができました。お疲れ様でした。あとはアプリの内容を充実させることに集中することができます。
ただし、ここで紹介した手順・構成がベストプラクティスとは限りません。今回は動くことを重視したため、セキュリティ面ではまだまだ手を入れないといけないところがあると思います。その点だけはご了承ください。