2018年4月30日月曜日

terraform + ECSを試す


terraform と ECS の学習のため、
下図のAWS環境を terraform で構築してみました。



ECSで試したかったことは以下のとおり。
  • EC2インスタンス1台でマイクロサービスのコンテナを4つ(backend,user,auth,worker)動かす。
  • スケールアウトできるように1サービス:1コンテナ(1タスク)にし、コンテナには、ALB経由でアクセスする。
  • workerコンテナは、awsvpc にして、プライベートサブネットに入れる。
  • SSMでEC2インスタンスの docker コマンドを実行する。
  • コンテナのログをCloudWatchLogsで収集する。
  • Route53にALBをDNS(インターナル)登録する。

実施した構築作業と動作確認の流れを、備忘録として、以下に記述します。

Dockerイメージの準備


まず、テスト用のマイクロサービスとして、下記のDockerイメージを2つ用意しました。
  • blue21/micro.backend
    backendコンテナで使用し、user,auth,workerにアクセスしてレスポンスを表示します。
  • blue21/micro.workers
    user, auth, worker コンテナで使用し、コンテナのIPアドレスを返します。
Dockerイメージは、ローカル環境(VirtualBoxのCentOS7)の docker-compose でビルドと動作確認を行いました。
今回作成した docker-compose のソースは、以下の Bitbucketからダウンロードできます。

上記ソースを使用したDockerイメージ準備作業の流れは、以下のとおり。
最終的に、DockerHUBにイメージを登録します。
イメージのサイズがECRの無料使用枠に収まらないと思ったので、DockerHUBに登録しました。

1. マイクロサービスの Docker イメージをビルドする。


docker-compose でイメージを2つ作成します。
# docker-compose build
# docker images
REPOSITORY               TAG                 IMAGE ID            CREATED             SIZE
blue21/micro.workers     latest              88fa4a7edec0        2 days ago          261MB
blue21/micro.backend     latest              cc75da278726        2 days ago          297MB

2. ローカル環境でDockerイメージの動作確認


docker-composeで コンテナを4つ起動して、動作確認します。
# docker-compose up -d
# docker-compose ps
 Name        Command       State           Ports
---------------------------------------------------------
auth      python3 app.py   Up      80/tcp
backend   python3 app.py   Up      0.0.0.0:5000->5000/tcp
user      python3 app.py   Up      80/tcp
worker    python3 app.py   Up      80/tcp
# curl http://localhost:5000
<!DOCTYPE html>
<html>
<head>
  <title>[demo] マイクロサービス</title>
</head>
<body>
  <h1>[demo] マイクロサービス</h1>

  <ul>

    <li><h2>worker</h2><strong>Service Response:</strong> こんにちは、worker です. Host は、worker.dev.blue21.local(172.18.0.4) です.
    </li>

    <li><h2>user</h2><strong>Service Response:</strong> こんにちは、user です. Host は、user.dev.blue21.local(172.18.0.2) です.
    </li>

    <li><h2>auth</h2><strong>Service Response:</strong> こんにちは、auth です. Host は、auth.dev.blue21.local(172.18.0.3) です.
    </li>

  </ul>

</body>

3. DockerイメージをDockerHUB に登録


Dockerイメージを DockerHUB の自分のアカウントに登録します。
# docker login
# docker push blue21/micro.backend:latest
# docker push blue21/micro.workers:latest

今回は、無償のパブリックなレポジトリとして登録したので、下記で参照できます。
https://hub.docker.com/u/blue21/

AWS環境構築


terraform でAWS環境を構築します。
terraform コマンドは、dockerコンテナを使用しました。(前回の記事を参照)

今回作成したソースは、以下の Bitbucket で参照できます。
https://bitbucket.org/blue21/aws-sample-ecs/src/master/

上記ソースでは、terraform の workspace を利用して 開発環境と本番環境を構築できるように考慮していますが、本番環境構築の動作確認はしていません。
また、terra.sh というシェルを用意して、dockerコンテナの terraform コマンドを実行しています。

上記ソースを使用した構築の流れは以下のとおり。
今回は、開発環境(workspace=dev)を構築します。ちなみに。本番環境の場合は workspace = prod になります。

1. envfile の準備


envfile にアクセスキー、シークレットアクセスキーを定義します。
今回は、Adminstrator 権限を持ったキーを使用しました。
AWS_ACCESS_KEY_ID=<アクセスキー>
AWS_SECRET_ACCESS_KEY=<シークレットアクセスキー>
envfile は terra.sh で使用し、/root/conf/envfile に配置します。

2. common.tfvars の準備


使用するリージョンを定義します。
今回は us-east-1 を使用するので、ECSで使用する EC2インスタンス用のAMIは、us-east-1 用です。
myip は、セキュリティグループの定義で使用します。myip に定義したIPアドレスのみEC2インスタンスへのSSH接続を許可します。
/*
 * COMMON VARIABLES
 *
 */

common = {
    # default
    default.region     = "us-east-1"         # リージョン
    default.project    = "demo"              # プロジェクト名
    default.myip       = "110.165.221.254"   # 管理者IP
    default.zone_name  = "blue21.local"      # DNS
}

3. terraform で AWSに network環境を作成


下記のコマンドでネットワーク環境を構築します。
VPC、サブネット、IGW、ルートテーブル、セキュリティグループを作成します。
# ./terra.sh 10.network init
# ./terra.sh 10.network workspace new dev
# ./terra.sh 10.network plan
# ./terra.sh 10.network apply

terraformで作成したリソースを、AWSコンソールで確認すると下図のようになります。

[VPC]

[サブネット]

[ルートテーブル]

[IGW]

[セキュリティグループ]

4. terraform で AWSに IAMロールを作成


下記のコマンドでIAMロールを作成します。
# ./terra.sh 20.iam init
# ./terra.sh 20.iam workspace new dev
# ./terra.sh 20.iam plan
# ./terra.sh 20.iam apply

terraformで作成したリソースを、AWSコンソールで確認すると下図のようになります。

[ロール]

4. terraform で AWSに ALBを作成


下記のコマンドでALBを作成します。
# ./terra.sh 30.ec2 init
# ./terra.sh 30.ec2 workspace new dev
# ./terra.sh 30.ec2 plan
# ./terra.sh 30.ec2 apply

terraformで作成したリソースを、AWSコンソールで確認すると下図のようになります。

[ターゲット]

[ロードバランサ]

7. terraform で AWSに ECSを作成


下記のコマンドでECSを作成します。
ここで作成するEC2インスタンスのキーペアは、"virginia_key" という名前にしています。
また、EC2インスタンスには、userdata を使用して、SSMエージェントをインストールしています。
# ./terra.sh 40.ecs init
# ./terra.sh 40.ecs workspace new dev
# ./terra.sh 40.ecs plan
# ./terra.sh 40.ecs apply

terraformで作成したリソースを、AWSコンソールで確認すると下図のようになります。

[EC2インスタンス]
ENIが2つ作成され、プライベートIPが2つ割当てられます。1つは、ネットワークタイプを "awsvpc" にした worker コンテナ用です。

[ECS: タスク定義]

[ECS: クラスタ]

[ECS: サービス]

[ECS: タスク]

[ECS: ECSインスタンス]

8. terraform で AWSに Route53 を作成


下記のコマンドでRoute53を作成します。
VPC内部で使用可能なインターナルなゾーンを作成します。
# ./terra.sh 50.r53 init
# ./terra.sh 50.r53 workspace new dev
# ./terra.sh 50.r53 plan
# ./terra.sh 50.r53 apply

terraformで作成したリソースを、AWSコンソールで確認すると下図のようになります。

[ゾーン]

[レコードセット]

動作確認


上記でAWS環境ができたので、いろいろ試します。

マイクロサービス


AWSの外側からALBにアクセスしてみます。
成功すると、以下のように各コンテナのIPアドレスが表示されます。
[root@centos701 ~]# curl http://demo-dev-alb-1527439969.us-east-1.elb.amazonaws.com
<!DOCTYPE html>
<html>
<head>
  <title>[demo] マイクロサービス</title>
</head>
<body>
  <h1>[demo] マイクロサービス</h1>

  <ul>

    <li><h2>worker</h2><strong>Service Response:</strong> こんにちは、worker です. Host は、worker.dev.blue21.local(10.0.10.104) です.
    </li>

    <li><h2>user</h2><strong>Service Response:</strong> こんにちは、user です. Host は、user.dev.blue21.local(172.17.0.3) です.
    </li>

    <li><h2>auth</h2><strong>Service Response:</strong> こんにちは、auth です. Host は、auth.dev.blue21.local(172.17.0.2) です.
    </li>

  </ul>

</body>
</html>[root@centos701 ~]#

こんどは、HTTPヘッダでホスト名を worker に変更して、 ALBにアクセスしてみます。
成功すると以下のように workerコンテナのIPアドレスが表示されます。
[root@centos701 ~]# curl -H "Host: worker.dev.blue21.local" http://demo-dev-alb-1527439969.us-east-1.elb.amazonaws.com
こんにちは、worker です. Host は、worker.dev.blue21.local(10.0.10.104) です.[root@centos701 ~]#

CloudWatchLogs


AWSコンソールで CLoudWatchLogs を参照すると、下図のとおり。
コンテナのログを参照できます。

[コンテナのログ一覧]

[backend のログ(アクセスログ)]

SSMでのコマンド実行


AWSコンソールの[EC2]>[SYSTEM MANAGER SERVICES]でコマンドを実行してみます。
ECS用のEC2インスタンス上で"docker ps"コマンドを実行すると下図のように表示されました。


Route53


VPC内部で、blue21.local のDNS名でマイクロサービスにアクセスしてみます。
ECS用のEC2インスタンスにSSHログインして、以下のように curl コマンドで backend に アクセスしてみました。
成功すると以下のように表示されます。
[ec2-user@ip-10-0-0-4 ~]$ curl http://backend.dev.blue21.local
<!DOCTYPE html>
<html>
<head>
  <title>[demo] マイクロサービス</title>
</head>
<body>
  <h1>[demo] マイクロサービス</h1>

  <ul>

    <li><h2>worker</h2><strong>Service Response:</strong> こんにちは、worker です. Host は、worker.dev.blue21.local(10.0.10.104) です.
    </li>

    <li><h2>user</h2><strong>Service Response:</strong> こんにちは、user です. Host は、user.dev.blue21.local(172.17.0.3) です.
    </li>

    <li><h2>auth</h2><strong>Service Response:</strong> こんにちは、auth です. Host は、auth.dev.blue21.local(172.17.0.2) です.
    </li>

  </ul>

</body>
</html>[ec2-user@ip-10-0-0-4 ~]$

user,auth,workerコンテナにアクセスすると、成功すれば、以下のよう表示されます。
[ec2-user@ip-10-0-0-4 ~]$ curl http://user.dev.blue21.local
こんにちは、user です. Host は、user.dev.blue21.local(172.17.0.3) です.[ec2-user@ip-10-0-0-4 ~]$
[ec2-user@ip-10-0-0-4 ~]$ curl http://auth.dev.blue21.local
こんにちは、auth です. Host は、auth.dev.blue21.local(172.17.0.2) です.[ec2-user@ip-10-0-0-4 ~]$
[ec2-user@ip-10-0-0-4 ~]$ curl http://worker.dev.blue21.local
こんにちは、worker です. Host は、worker.dev.blue21.local(10.0.10.104) です.[ec2-user@ip-10-0-0-4 ~]$
[ec2-user@ip-10-0-0-4 ~]$

コンテナのスケールアウト


user コンテナを手動でスケールアウトしてみます。
modules/ecs/main.tf の 下記 "desired_count" を 2 に修正して、user コンテナを2つ起動するようにソースを変更します。
resource "aws_ecs_service" "user" {
  name                  = "${local.name_prefix}-user"
  cluster               = "${aws_ecs_cluster.default.id}"
  task_definition       = "${aws_ecs_task_definition.user.arn}"
  desired_count         = 2
  health_check_grace_period_seconds = 30
  iam_role              = "${var.m-role-ecs.["ecs-service-role-arn"]}"

  load_balancer {
    target_group_arn    = "${var.m-alb.["target-user-id"]}"
    container_name      = "user"
    container_port      = 80
  }
}

terraform で上記の変更を反映します。
# ./terra.sh 40.ecs apply

AWSコンソールで変更結果を確認すると下図のとおり。

[userサービスのコンテナが2つある]

[ALBの user用ターゲットに、コンテナが追加されている]

[CloudwatchLogs が追加されている]

マイクロサービスにアクセスすると、以下のように user のIPアドレスが変わります。
# curl http://demo-dev-alb-1527439969.us-east-1.elb.amazonaws.com
<!DOCTYPE html>
<html>
<head>
  <title>[demo] マイクロサービス</title>
</head>
<body>
  <h1>[demo] マイクロサービス</h1>

  <ul>

    <li><h2>worker</h2><strong>Service Response:</strong> こんにちは、worker です. Host は、worker.dev.blue21.local(10.0.10.104) です.
    </li>

    <li><h2>user</h2><strong>Service Response:</strong> こんにちは、user です. Host は、user.dev.blue21.local(172.17.0.3) です.
    </li>

    <li><h2>auth</h2><strong>Service Response:</strong> こんにちは、auth です. Host は、auth.dev.blue21.local(172.17.0.2) です.
    </li>

  </ul>

</body>
</html>
下記は、user コンテナのIPアドレスが上記と異なっているので、ALBで振り分けできてることがわかります。
# curl http://demo-dev-alb-1527439969.us-east-1.elb.amazonaws.com
<!DOCTYPE html>
<html>
<head>
  <title>[demo] マイクロサービス</title>
</head>
<body>
  <h1>[demo] マイクロサービス</h1>

  <ul>

    <li><h2>worker</h2><strong>Service Response:</strong> こんにちは、worker です. Host は、worker.dev.blue21.local(10.0.10.104) です.
    </li>

    <li><h2>user</h2><strong>Service Response:</strong> こんにちは、user です. Host は、user.dev.blue21.local(172.17.0.5) です.
    </li>

    <li><h2>auth</h2><strong>Service Response:</strong> こんにちは、auth です. Host は、auth.dev.blue21.local(172.17.0.2) です.
    </li>

  </ul>

</body>
</html>

あとかたずけ


遊び終わったら、上記で作成したAWS環境を、以下の順番で削除します。お金がもったいないので。
# ./terra.sh 50.r53 destroy
# ./terra.sh 40.ecs destroy
# ./terra.sh 30.ec2 destroy
# ./terra.sh 20.iam destroy
# ./terra.sh 10.network destroy

ちなみに、夜などAWSをさわらないときは、
お金のかからない network, iam だけ残して、ec2, ecs, r53 は削除し、検証時に毎回、ec2, ecs, r53 を作成してました。


2018年4月10日火曜日

Terraformのベストプラクティスを試す


下記ページのベストプラクティスを試してみました。
Terraform Best Practices in 2017

ディレクトリ構成は、ちょっと変えて、以下のようにし、
tfstate は s3 ではなく、local に保存して管理するようにしました。
.
├── modules
│   ├── ec2
│   ├── iam
│   ├── route-table
│   ├── security-group
│   ├── subnet-private
│   ├── subnet-public
│   ├── vpc
│   └── vpc-endpoint
└── targets
    ├── 10.network
    ├── 20.iam
    └── 30.ec2

作成したソースは、Bitbucket からダウンロードできます。

terraformコマンドで、以下の順番でAWS環境を構築します。

  1. ネットワーク作成(vpc, igw, subnet, route-table, security-group)
  2. IAMロール作成(EC2インスタンス用)
  3. EC2インスタンス作成

なお、今回、terraform コマンドは、オフィシャルのDockerイメージを使用します。

動作確認


上記Bitbucketのterraformサンプルは、AWSに本番環境と開発環境を構築する想定で作っています。

以下は、開発環境を構築する手順です。
本番環境は、workspace を prod に切り替えるだけで、手順は開発環境と同じです。

環境差分は、targetsディレクトリ配下の variable.tf の変数に定義しています。
以下の例では、"prod."で始まる変数が、本番環境用の定義です。
"dev." で始まる変数が、開発環境用の定義ですが、未定義の場合は、"default."で始まる変数が使われます。
variable "vpc" {
    type = "map"
    default = {
        default.cidr       = "10.0.0.0/16"
        default.public-a   = "10.0.10.0/24"
        default.public-b   = "10.0.11.0/24"
        default.private-a  = "10.0.21.0/24"
        default.private-b  = "10.0.22.0/24"

        prod.cidr          = "10.1.0.0/16"
        prod.public-a      = "10.1.10.0/24"
        prod.public-b      = "10.1.11.0/24"
        prod.private-a     = "10.1.21.0/24"
        prod.private-b     = "10.1.22.0/24"
    }
}

envfile の用意


envfile に docker に渡す環境変数を定義します。
tfファイルにアクセスキーを書きたくなかったので環境変数で定義することにしました。
アクセスキーは、ネットワーク、IAM、EC2を作成できる権限が必要です。
envfileの内容は以下のとおり。
AWS_REGION=<リージョン>
AWS_ACCESS_KEY_ID=<アクセスキー>
AWS_SECRET_ACCESS_KEY=<シークレットアクセスキー>

terraform の Dockerイメージの pull


オフィシャルの Dockerイメージをプルします。
# docker pull hashicorp/terraform:light

ネットワーク作成


terraform で init を実行します。
カレントディレクトリを dockerコンテナ内の /work にマウントして terraform コマンドを実行します。
[root@centos701 aws-sample-terraform]# docker run -it --rm -v `pwd`:/work --env-file=./envfile -w /work/targets/10.network hashicorp/terraform:light init
Initializing modules...
- module.e-vpc
  Getting source "../../modules/vpc"
- module.e-subnet-public
  Getting source "../../modules/subnet-public"
- module.e-subnet-private
  Getting source "../../modules/subnet-private"
- module.e-route-table
  Getting source "../../modules/route-table"
- module.e-security-group
  Getting source "../../modules/security-group"
- module.e-vpc-endpoint
  Getting source "../../modules/vpc-endpoint"

Initializing the backend...

Successfully configured the backend "local"! Terraform will automatically
use this backend unless the backend configuration changes.

Initializing provider plugins...
- Checking for available provider plugins on https://releases.hashicorp.com...
- Downloading plugin for provider "aws" (1.14.0)...

The following providers do not have any version constraints in configuration,
so the latest version was installed.

To prevent automatic upgrades to new major versions that may contain breaking
changes, it is recommended to add version = "..." constraints to the
corresponding provider blocks in configuration, with the constraint strings
suggested below.

* provider.aws: version = "~> 1.14"

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

workspace を作成します。dev(開発環境) を新規で作成します。
[root@centos701 aws-sample-terraform]# docker run -it --rm -v `pwd`:/work --env-file=./envfile -w /work/targets/10.network hashicorp/terraform:light workspace new dev
Created and switched to workspace "dev"!

You're now on a new, empty workspace. Workspaces isolate their state,
so if you run "terraform plan" Terraform will not see any existing state
for this configuration.

workspace で dev が選択されていることを確認します。
[root@centos701 aws-sample-terraform]# docker run -it --rm -v `pwd`:/work --env-file=./envfile -w /work/targets/10.network hashicorp/terraform:light workspace list
  default
* dev

plan を実行します。
[root@centos701 aws-sample-terraform]# docker run -it --rm -v `pwd`:/work --env-file=./envfile -w /work/targets/10.network hashicorp/terraform:light plan
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.


------------------------------------------------------------------------

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  + module.e-route-table.aws_route_table.private
      id:                                          <computed>
      propagating_vgws.#:                          <computed>
      route.#:                                     <computed>
      tags.%:                                      "1"
      tags.Name:                                   "demo-dev-private"
      vpc_id:                                      "${lookup(var.m-vpc, \"vpc_id\")}"

  + module.e-route-table.aws_route_table.public
      id:                                          <computed>
      propagating_vgws.#:                          <computed>
      route.#:                                     "1"
      route.~1608397107.cidr_block:                "0.0.0.0/0"
      route.~1608397107.egress_only_gateway_id:    ""
      route.~1608397107.gateway_id:                "${lookup(var.m-vpc, \"igw_id\")}"
      route.~1608397107.instance_id:               ""
      route.~1608397107.ipv6_cidr_block:           ""
      route.~1608397107.nat_gateway_id:            ""
      route.~1608397107.network_interface_id:      ""
      route.~1608397107.vpc_peering_connection_id: ""
      tags.%:                                      "1"
      tags.Name:                                   "demo-dev-public"
      vpc_id:                                      "${lookup(var.m-vpc, \"vpc_id\")}"

  + module.e-route-table.aws_route_table_association.private-a
      id:                                          <computed>
      route_table_id:                              "${aws_route_table.private.id}"
      subnet_id:                                   "${lookup(var.m-subnet-private, \"subnet-private-a\")}"

  + module.e-route-table.aws_route_table_association.private-b
      id:                                          <computed>
      route_table_id:                              "${aws_route_table.private.id}"
      subnet_id:                                   "${lookup(var.m-subnet-private, \"subnet-private-a\")}"

  + module.e-route-table.aws_route_table_association.public-a
      id:                                          <computed>
      route_table_id:                              "${aws_route_table.public.id}"
      subnet_id:                                   "${lookup(var.m-subnet-public, \"subnet-public-a\")}"

  + module.e-route-table.aws_route_table_association.public-b
      id:                                          <computed>
      route_table_id:                              "${aws_route_table.public.id}"
      subnet_id:                                   "${lookup(var.m-subnet-public, \"subnet-public-b\")}"

  + module.e-security-group.aws_security_group.servers
      id:                                          <computed>
      arn:                                         <computed>
      description:                                 "servers security group"
      egress.#:                                    "1"
      egress.482069346.cidr_blocks.#:              "1"
      egress.482069346.cidr_blocks.0:              "0.0.0.0/0"
      egress.482069346.description:                ""
      egress.482069346.from_port:                  "0"
      egress.482069346.ipv6_cidr_blocks.#:         "0"
      egress.482069346.prefix_list_ids.#:          "0"
      egress.482069346.protocol:                   "-1"
      egress.482069346.security_groups.#:          "0"
      egress.482069346.self:                       "false"
      egress.482069346.to_port:                    "0"
      ingress.#:                                   "2"
      ingress.2541437006.cidr_blocks.#:            "1"
      ingress.2541437006.cidr_blocks.0:            "0.0.0.0/0"
      ingress.2541437006.description:              ""
      ingress.2541437006.from_port:                "22"
      ingress.2541437006.ipv6_cidr_blocks.#:       "0"
      ingress.2541437006.protocol:                 "tcp"
      ingress.2541437006.security_groups.#:        "0"
      ingress.2541437006.self:                     "false"
      ingress.2541437006.to_port:                  "22"
      ingress.753360330.cidr_blocks.#:             "0"
      ingress.753360330.description:               ""
      ingress.753360330.from_port:                 "0"
      ingress.753360330.ipv6_cidr_blocks.#:        "0"
      ingress.753360330.protocol:                  "-1"
      ingress.753360330.security_groups.#:         "0"
      ingress.753360330.self:                      "true"
      ingress.753360330.to_port:                   "0"
      name:                                        "demo-dev-servers"
      owner_id:                                    <computed>
      revoke_rules_on_delete:                      "false"
      vpc_id:                                      "${var.m-vpc[\"vpc_id\"]}"

  + module.e-subnet-private.aws_subnet.private-a
      id:                                          <computed>
      assign_ipv6_address_on_creation:             "false"
      availability_zone:                           "us-east-1a"
      cidr_block:                                  "10.0.21.0/24"
      ipv6_cidr_block:                             <computed>
      ipv6_cidr_block_association_id:              <computed>
      map_public_ip_on_launch:                     "false"
      tags.%:                                      "1"
      tags.Name:                                   "demo-dev-private-a"
      vpc_id:                                      "${lookup(var.m-vpc, \"vpc_id\")}"

  + module.e-subnet-private.aws_subnet.private-b
      id:                                          <computed>
      assign_ipv6_address_on_creation:             "false"
      availability_zone:                           "us-east-1b"
      cidr_block:                                  "10.0.22.0/24"
      ipv6_cidr_block:                             <computed>
      ipv6_cidr_block_association_id:              <computed>
      map_public_ip_on_launch:                     "false"
      tags.%:                                      "1"
      tags.Name:                                   "demo-dev-private-b"
      vpc_id:                                      "${lookup(var.m-vpc, \"vpc_id\")}"

  + module.e-subnet-public.aws_subnet.public-a
      id:                                          <computed>
      assign_ipv6_address_on_creation:             "false"
      availability_zone:                           "us-east-1a"
      cidr_block:                                  "10.0.10.0/24"
      ipv6_cidr_block:                             <computed>
      ipv6_cidr_block_association_id:              <computed>
      map_public_ip_on_launch:                     "false"
      tags.%:                                      "1"
      tags.Name:                                   "demo-dev-public-a"
      vpc_id:                                      "${lookup(var.m-vpc, \"vpc_id\")}"

  + module.e-subnet-public.aws_subnet.public-b
      id:                                          <computed>
      assign_ipv6_address_on_creation:             "false"
      availability_zone:                           "us-east-1b"
      cidr_block:                                  "10.0.11.0/24"
      ipv6_cidr_block:                             <computed>
      ipv6_cidr_block_association_id:              <computed>
      map_public_ip_on_launch:                     "false"
      tags.%:                                      "1"
      tags.Name:                                   "demo-dev-public-b"
      vpc_id:                                      "${lookup(var.m-vpc, \"vpc_id\")}"

  + module.e-vpc-endpoint.aws_vpc_endpoint.ec2
      id:                                          <computed>
      cidr_blocks.#:                               <computed>
      dns_entry.#:                                 <computed>
      network_interface_ids.#:                     <computed>
      policy:                                      <computed>
      prefix_list_id:                              <computed>
      private_dns_enabled:                         "true"
      route_table_ids.#:                           <computed>
      security_group_ids.#:                        <computed>
      service_name:                                "com.amazonaws.us-east-1.ec2"
      state:                                       <computed>
      subnet_ids.#:                                <computed>
      vpc_endpoint_type:                           "Interface"
      vpc_id:                                      "${var.m-vpc[\"vpc_id\"]}"

  + module.e-vpc-endpoint.aws_vpc_endpoint.s3
      id:                                          <computed>
      cidr_blocks.#:                               <computed>
      dns_entry.#:                                 <computed>
      network_interface_ids.#:                     <computed>
      policy:                                      <computed>
      prefix_list_id:                              <computed>
      private_dns_enabled:                         "false"
      route_table_ids.#:                           <computed>
      security_group_ids.#:                        <computed>
      service_name:                                "com.amazonaws.us-east-1.s3"
      state:                                       <computed>
      subnet_ids.#:                                <computed>
      vpc_endpoint_type:                           "Gateway"
      vpc_id:                                      "${var.m-vpc[\"vpc_id\"]}"

  + module.e-vpc.aws_internet_gateway.vpc-igw
      id:                                          <computed>
      tags.%:                                      "1"
      tags.Name:                                   "demo-dev-igw"
      vpc_id:                                      "${aws_vpc.vpc.id}"

  + module.e-vpc.aws_vpc.vpc
      id:                                          <computed>
      assign_generated_ipv6_cidr_block:            "false"
      cidr_block:                                  "10.0.0.0/16"
      default_network_acl_id:                      <computed>
      default_route_table_id:                      <computed>
      default_security_group_id:                   <computed>
      dhcp_options_id:                             <computed>
      enable_classiclink:                          <computed>
      enable_classiclink_dns_support:              <computed>
      enable_dns_hostnames:                        "true"
      enable_dns_support:                          "true"
      instance_tenancy:                            <computed>
      ipv6_association_id:                         <computed>
      ipv6_cidr_block:                             <computed>
      main_route_table_id:                         <computed>
      tags.%:                                      "1"
      tags.Name:                                   "demo-dev-vpc"


Plan: 15 to add, 0 to change, 0 to destroy.

------------------------------------------------------------------------

Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.

apply を実行します。
[root@centos701 aws-sample-terraform]# docker run -it --rm -v `pwd`:/work --env-file=./envfile -w /work/targets/10.network hashicorp/terraform:light apply

IAMロールの作成

上記「ネットワーク作成」と同じ手順で、ロールを作成します。
[root@centos701 aws-sample-terraform]# docker run -it --rm -v `pwd`:/work --env-file=./envfile -w /work/targets/20.iam hashicorp/terraform:light init
[root@centos701 aws-sample-terraform]# docker run -it --rm -v `pwd`:/work --env-file=./envfile -w /work/targets/20.iam hashicorp/terraform:light workspace new dev
[root@centos701 aws-sample-terraform]# docker run -it --rm -v `pwd`:/work --env-file=./envfile -w /work/targets/20.iam hashicorp/terraform:light workspace list
[root@centos701 aws-sample-terraform]# docker run -it --rm -v `pwd`:/work --env-file=./envfile -w /work/targets/20.iam hashicorp/terraform:light plan
[root@centos701 aws-sample-terraform]# docker run -it --rm -v `pwd`:/work --env-file=./envfile -w /work/targets/20.iam hashicorp/terraform:light apply

EC2インスタンスの作成

上記「ネットワーク作成」と同じ手順で、EC2インスタンスを作成します。
[root@centos701 aws-sample-terraform]# docker run -it --rm -v `pwd`:/work --env-file=./envfile -w /work/targets/30.ec2 hashicorp/terraform:light init
[root@centos701 aws-sample-terraform]# docker run -it --rm -v `pwd`:/work --env-file=./envfile -w /work/targets/30.ec2 hashicorp/terraform:light workspace new dev
[root@centos701 aws-sample-terraform]# docker run -it --rm -v `pwd`:/work --env-file=./envfile -w /work/targets/30.ec2 hashicorp/terraform:light workspace list
[root@centos701 aws-sample-terraform]# docker run -it --rm -v `pwd`:/work --env-file=./envfile -w /work/targets/30.ec2 hashicorp/terraform:light plan
[root@centos701 aws-sample-terraform]# docker run -it --rm -v `pwd`:/work --env-file=./envfile -w /work/targets/30.ec2 hashicorp/terraform:light apply





2018年4月8日日曜日

Docker + emacs で markdown文書をプレビューする環境をつくる

普段は、CentOS7 + emacs を使用しています。

README.md などの markdown文書を、emacs でプレビューできる環境を作ろうとしたが、CentOS7より、ubuntu のほうが簡単そうだったので、Dcoker(ubuntu)で emacs 環境を作ってみた。

ubuntu + emacsでmarkdown 文書をプレビューする環境は、下記URLのページを参考にしました。
emacs-w3mでmarkdown原稿をプレビューする

1. Docker イメージの作成


用意したファイルは、以下のとおり
[root@centos701 docker]# tree -a emacs-md/
emacs-md/
├── .emacs
└── Dockerfile

0 directories, 2 files

Dockerfile の内容は以下のとおり。
ubuntu のバージョンは 16.04 です。
FROM ubuntu

RUN apt-get update

# LANG
RUN apt-get install -y language-pack-ja-base language-pack-ja
RUN locale-gen ja_JP.UTF-8
ENV LANG ja_JP.UTF-8
ENV LANGUAGE ja_JP:ja
ENV LC_ALL ja_JP.UTF-8

# TZ
RUN cp /etc/apt/sources.list /etc/apt/sources.list.bk
RUN sed -i -e "s%http://archive.ubuntu.com/ubuntu/%http://ftp.jaist.ac.jp/pub/Linux/ubuntu/%g" /etc/apt/sources.list
ENV TZ Asia/Tokyo
RUN apt-get update \
  && apt-get install -y tzdata \
  && rm -rf /var/lib/apt/lists/* \
  && echo "${TZ}" > /etc/timezone \
  && rm /etc/localtime \
  && ln -s /usr/share/zoneinfo/Asia/Tokyo /etc/localtime \
  && dpkg-reconfigure -f noninteractive tzdata
RUN cp /etc/apt/sources.list.bk /etc/apt/sources.list
RUN apt-get update

# emacs
RUN apt-get install -y markdown emacs-goodies-el w3m-el ibus-mozc emacs-mozc emacs-mozc-bin
ADD .emacs /root/

# entrypoint
ENTRYPOINT [ "emacs", "-nw" ]

.emacs の内容は以下のとおり。
(require 'markdown-mode)
(add-to-list 'auto-mode-alist '("\\.md\\'" . markdown-mode))
(define-key markdown-mode-map (kbd "\C-c \C-c \C-e") 'markdown-export)
(require 'w3m)
(define-key markdown-mode-map (kbd "\C-c \C-c \C-v")
  (lambda ()
    (interactive)
    (setq html-file-name (concat (file-name-sans-extension (buffer-file-name)) ".html"))
    (markdown-export html-file-name)
    (if (one-window-p) (split-window-right))
    (other-window 1)

    ;; (2016/05/23)
    ;; (w3m-find-file html-file-name)

    ;; (2016/05/28)
    ;; (if (buffer-file-name) (w3m-find-file html-file-name) (w3m-reload-this-page))

    ;; (2016/05/29)
    (if (get-buffer "*w3m*")
        (prog2 (switch-to-buffer "*w3m*") (w3m-reload-this-page)) (w3m-find-file html-file-name))

    (other-window 1)))

(require 'mozc)
(set-language-environment "Japanese")
(setq default-input-method "japanese-mozc")
(prefer-coding-system 'utf-8)

Dockerイメージをビルドします。
[root@centos701 emacs-md]# docker build . --rm -t emacs-md

Dockerイメージを確認します。
[root@centos701 emacs-md]# docker images
REPOSITORY            TAG                 IMAGE ID            CREATED             SIZE
emacs-md              latest              448bd44ed933        25 minutes ago      992MB

2. 動作確認


以下のようにして、Dockerイメージの emacs を起動します。
"-v" で カレントディレクトリを コンテナの /work にマウントし、emacs で /work 配下を編集するようにします。
[root@centos701 sandbox]# ls
README.md  environments  memo  modules
[root@centos701 sandbox]# docker run -it --rm -v `pwd`:/work emacs-md /work

emacs が起動すると、下図のようにカレントディレクトリの内容が一覧表示されます。


emacs で README.md を開くと、下図のように表示されます。


[Ctrl-c]+[Ctrl-c]+[Ctrl-v]で、下図のように、左右に分割表示されます。
左側がソースで、右側がプレビューです。


カレントディレクトリに markdonw -> html に変換したファイルが作成されるので、不要なら削除します。
[root@centos701 sandbox]# ls
README.html  README.md  environments  memo  modules






2018年4月4日水曜日

起動中のDockerコンテナに入る


起動中の Dockerコンテナに入りたい。。。

いつも忘れるのでメモ。

まず、docker-compose を使用して、コンテナを起動します。
[root@centos701 nginx]# docker-compose up -d
Starting nginx_nginx_1 ... done

起動状態を確認します。
[root@centos701 nginx]# docker-compose ps
    Name              Command          State                       Ports
---------------------------------------------------------------------------------------------
nginx_nginx_1   nginx -g daemon off;   Up      0.0.0.0:28080->80/tcp, 0.0.0.0:28081->8081/tcp

docker-compose.yml で定義したサービス名を確認します。
[root@centos701 nginx]# docker-compose ps --service
nginx

docker-composeコマンドを使用する場合は、サービス名を指定してコンテナに入ります。
[root@centos701 nginx]# docker-compose exec nginx /bin/bash
root@106052b93dcb:/#

dockerコマンドを使用する場合は、コンテナ名を指定してコンテナに入ります。
[root@centos701 nginx]# docker exec -it nginx_nginx_1 /bin/bash
root@106052b93dcb:/#