• トップ
  • ブログ一覧
  • 【macOS】LocalStack+terraformでEC2+RDSを立ててみた
  • 【macOS】LocalStack+terraformでEC2+RDSを立ててみた

    ハク(エンジニア)ハク(エンジニア)
    2023.06.16

    IT技術

    注意

    • LocalStackのPro版(有料版)のAPIキーが必要
      • Pro版の体験版(14日間)があるので、そちらを使用しています
    • LocalStackとterraformとAWSのネットワーク設定周りは素人のため、間違っている箇所があるかもしれないがご容赦ください

    準備

    LocalStackをインストール

    • 参考: https://docs.localstack.cloud/getting-started/installation
      • 僕はLocalStack CLIでインストール
    • 下記ツールが必要のため、事前にインストール
      • python (version: 3.7 ~ 3.10)
      • pip
      • docker
    • LocalStackをインストール
      1brew install localstack
    • LocalStackがインストールされていることを確認
      1$ localstack --version
      22.1.0
    • LocalStack Pro版のAPIキーを環境変数に登録
      1export LOCALSTACK_API_KEY=xxxxxxxxxx
    • LocalStackを起動
      1$ localstack start -d
      2
      3     __                     _______ __             __
      4    / /   ____  _________ _/ / ___// /_____ ______/ /__
      5   / /   / __ \/ ___/ __ `/ /\__ \/ __/ __ `/ ___/ //_/
      6  / /___/ /_/ / /__/ /_/ / /___/ / /_/ /_/ / /__/ ,<
      7 /_____/\____/\___/\__,_/_//____/\__/\__,_/\___/_/|_|
      8
      9 💻 LocalStack CLI 2.1.0
      10
      11[10:41:13] starting LocalStack in Docker mode 🐳               localstack.py:142
      122023-06-09T10:41:15.565  INFO --- [  MainThread] l.bootstrap.licensing      : Successfully activated API key
      132023-06-09T10:41:15.880  INFO --- [  MainThread] localstack.utils.bootstrap : Execution of "prepare_host" took 1896.32ms
      14[10:41:15] preparing environment                                bootstrap.py:630
      15[10:41:16] configuring container                                bootstrap.py:638
      16[10:41:17] starting container                                   bootstrap.py:645
      17[10:41:18] detaching                                            bootstrap.py:649
    • LocalStackが起動していることを確認
      1$ localstack status
      2┌─────────────────┬───────────────────────────────────────────────────────┐
      3│ Runtime version │ 2.1.1.dev                                             │
      4│ Docker image    │ tag: latest, id: 9ff2ae7ae1a0, 📆 2023-06-02T11:46:415│ Runtime status  │ ✔ running (name: "localstack_main", IP: 172.17.0.2)6└─────────────────┴───────────────────────────────────────────────────────┘
      7
      8$ docker ps
      9CONTAINER ID   IMAGE                       COMMAND                  CREATED         STATUS                   PORTS                                                                                                                                    NAMES
      105f55c6aea975   localstack/localstack-pro   "docker-entrypoint.sh"   9 minutes ago   Up 9 minutes (healthy)   127.0.0.1:443->443/tcp, 127.0.0.1:4510-4559->4510-4559/tcp, 0.0.0.0:53->53/tcp, 0.0.0.0:53->53/udp, 127.0.0.1:4566->4566/tcp, 5678/tcp   localstack_main
      • IPアドレスは必要なのでメモを取る

    terraformをインストール

    • 参考: https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli
      • 僕はHomebrew on OS Xでインストール
    • terraformのリポジトリを追加
      1brew tap hashicorp/tap
    • terraformをインストール
      1brew install hashicorp/tap/terraform
    • terraformがインストールされていることを確認
      1$ terraform version
      2Terraform v1.4.6
      3on darwin_arm64
      4+ provider registry.terraform.io/hashicorp/aws v5.1.0
      5+ provider registry.terraform.io/hashicorp/http v3.3.0
      6+ provider registry.terraform.io/hashicorp/local v2.4.0
      7+ provider registry.terraform.io/hashicorp/tls v4.0.4

    EC2で使うイメージを用意する

    • 参考: https://docs.localstack.cloud/user-guide/aws/elastic-compute-cloud/#base-images
    • ubuntu:focalのイメージをpullします
      1docker pull ubuntu:focal
    • イメージがpullされていることを確認
      1$ docker images
      2REPOSITORY   TAG     IMAGE ID       CREATED       SIZE
      3... (中略) ...
      4ubuntu       focal   758cd4ebb217   8 weeks ago   65.7MB
      5... (中略) ...
    • LocalStack用のtagを追加
      1docker tag ubuntu:focal localstack-ec2/ubuntu-focal-ami:ami-000001
    • tagが追加されたことを確認
      1$ docker images
      2REPOSITORY                        TAG          IMAGE ID       CREATED       SIZE
      3... (中略) ...
      4localstack-ec2/ubuntu-focal-ami   ami-000001   758cd4ebb217   8 weeks ago   65.7MB
      5ubuntu                            focal        758cd4ebb217   8 weeks ago   65.7MB
      6... (中略) ...

    AWSプロフィールを設定

    • aws-cliで設定
      • AWS Access Key ID: dummy
      • AWS Secret Access Key: dummy
      • Default region name: ap-northeast-1
      • Default output format: json
      1$ aws configure --profile localstack
      2AWS Access Key ID [None]: dummy
      3AWS Secret Access Key [None]: dummy
      4Default region name [None]: ap-northeast-1
      5Default output format [None]: json
    • AWSプロフィールが設定されていることを確認
      1$ aws configure list --profile localstack
      2      Name                    Value             Type    Location
      3      ----                    -----             ----    --------
      4   profile               localstack           manual    --profile
      5access_key     ****************ummy shared-credentials-file
      6secret_key     ****************ummy shared-credentials-file
      7    region           ap-northeast-1      config-file    ~/.aws/config

    サーバー構成図

    1+----------------------------------------------+
    2| +--------------------------------+           |
    3| | RDS                            |           |
    4| | (MySQL)                        | <---+     |
    5| | port: determined by LocalStack |     |     |
    6| +--------------------------------+     |     |
    7|                                        |     |
    8|                                        |     |
    9|                                        |     |
    10| +------------+                +------------+ |
    11| | web-server |                | app-server | |
    12| | (nginx)    | -------------> | (golang)   | |
    13| | port: 80   |                | port: 8080 | |
    14| +------------+                +------------+ |
    15+----------------------------------------------+
    • RDS: LocalStackのコンテナー内にMySQLが起動する
    • web-server: 一つのdockerコンテナーとして作られる
      • web-serverの役割は通信の出入りで、リクエストが来たらapp-serverに通す(リバースプロキシ)
    • app-server: 一つのdockerコンテナーとして作られる
      • リクエストのIDをMySQLに格納されているデータを取得し、その結果を返却するプログラム

    terraformでEC2とRDSを構築

    • ディレクトリ構図
      1.
      2├── main.tf
      3├── output.tf
      4├── provider.tf
      5├── ec2
      6│   ├── keypair.tf
      7│   ├── main.tf
      8│   ├── output.tf
      9│   └── variables.tf
      10├── rds
      11│   ├── main.tf
      12│   └── variables.tf
      13└── vpc
      14    ├── main.tf
      15    └── output.tf
      • 上記のファイルはgit(url)に上げています
    • initとplanをします
      1$ terraform init
      2$ terraform plan
    • 内容を確認したらapplyを実行します
      1$ terraform apply
      • 途中でプロンプトが出るので、planと同じ内容出ていたらyesを打ちます
        1Do you want to perform these actions?
        2Terraform will perform the actions described above.
        3Only 'yes' will be accepted to approve.
        4
        5Enter a value: yes
    • EC2とRDSが起動していることを確認
      • EC2確認
        • dockerのコンテナーを確認
          1$ docker ps
          2CONTAINER ID   IMAGE                                        COMMAND                  CREATED          STATUS                    PORTS                                                                                                                                    NAMES
          3f16e0697c324   localstack-ec2/ubuntu-focal-ami:ami-000001   "sleep 43200"            17 minutes ago   Up 17 minutes             0.0.0.0:32983->22/tcp, 0.0.0.0:60385->80/tcp, 0.0.0.0:35709->8080/tcp                                                                    localstack-ec2.i-85a837419413c12d9
          4c9e63e3ae05b   localstack-ec2/ubuntu-focal-ami:ami-000001   "sleep 43200"            17 minutes ago   Up 17 minutes             0.0.0.0:22->22/tcp, 0.0.0.0:80->80/tcp, 0.0.0.0:8080->8080/tcp                                                                           localstack-ec2.i-0265072bfb2fbdc0a
          5ed08d7441d54   localstack/localstack-pro                    "docker-entrypoint.sh"   20 minutes ago   Up 20 minutes (healthy)   127.0.0.1:443->443/tcp, 127.0.0.1:4510-4559->4510-4559/tcp, 0.0.0.0:53->53/tcp, 0.0.0.0:53->53/udp, 127.0.0.1:4566->4566/tcp, 5678/tcp   localstack_main
          • dockerのコンテナーIDc9e63e3ae05bf16e0697c324は立てられたEC2で、起動していることが確認できた
            • c9e63e3ae05bはweb-serverとします
            • f16e0697c324はapp-serverとします
        • LocalStackのログを確認
          1$ localstack logs
          2... (中略) ...
          32023-06-09T03:59:02.385  INFO --- [   asgi_gw_4] l.s.ec2.vmmanager.docker   : Instance i-0265072bfb2fbdc0a will be accessible via SSH at: 127.0.0.1:22, 172.17.0.3:22
          42023-06-09T03:59:02.385  INFO --- [   asgi_gw_4] l.s.ec2.vmmanager.docker   : Instance i-0265072bfb2fbdc0a port mappings (container -> host): {'8080/tcp': 8080, '80/tcp': 80, '22/tcp': 22}
          52023-06-09T03:59:02.398  INFO --- [   asgi_gw_4] localstack.request.aws     : AWS ec2.RunInstances => 200
          62023-06-09T03:59:02.480  INFO --- [   asgi_gw_0] l.s.ec2.vmmanager.docker   : Instance i-85a837419413c12d9 will be accessible via SSH at: 127.0.0.1:32983, 172.17.0.4:22
          72023-06-09T03:59:02.480  INFO --- [   asgi_gw_0] l.s.ec2.vmmanager.docker   : Instance i-85a837419413c12d9 port mappings (container -> host): {'8080/tcp': 35709, '80/tcp': 60385, '22/tcp': 32983}
          82023-06-09T03:59:02.492  INFO --- [   asgi_gw_0] localstack.request.aws     : AWS ec2.RunInstances => 200
          9... (中略) ...
          • インスタンスIDi-0265072bfb2fbdc0ai-85a837419413c12d9は起動していることが確認できた
          • IPアドレスとポート番号は必要なのでメモを取る
      • RDS確認
        • LocalStackのコンテナーに入る
          • ↑の出力からコンテナーIDはed08d7441d54
          1docker exec -it ed08d7441d54 bash
        • プロセス確認
          1root@ed08d7441d54:/opt/code/localstack# ps aux
          2USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
          3root         1  0.0  0.1  11372  8628 ?        Ss   03:56   0:00 /opt/code/local
          4root        15  0.4  4.4 1921908 359844 ?      Sl   03:56   0:07 /opt/code/local
          5root      1354  0.0  0.0   2056   464 ?        Ss   03:58   0:00 /bin/sh -c mysq
          6mysql     1355  0.0  0.9 1418084 80080 ?       Sl   03:58   0:00 mysqld --no-def
          7root      3710  0.5  0.0   5844  3452 pts/0    Ss   04:28   0:00 bash
          8root      3716  0.0  0.0   8340  2840 pts/0    R+   04:28   0:00 ps aux
        • ポート番号はLocalStackのログで確認
          1$ localstack logs | grep rds
          2... (中略) ...
          32023-06-09T03:58:59.048  INFO --- [functhread38] l.s.rds.engine_mariadb     : Starting MySQL (MariaDB) RDS server on port 4510 (backend port 4510) - database "terraform_practice", user "terraform"
          4... (中略) ...
          • ポート番号は4510であることがわかりました
        • MySQLは起動していることが確認できた

    接続情報

    1type                docker-container-id     ip-address    port
    2ec2 (web-server)    c9e63e3ae05b            172.17.0.3    80->80; 8080->8080
    3ec2 (app-server)    f16e0697c324            172.17.0.4    60385->80; 35709->8080
    4rds                 ed08d7441d54            172.17.0.2    4510

    RDSデータ準備

    • MySQLにログイン
      1root@ed08d7441d54:/opt/code/localstack# mysql -h 127.0.0.1 -P 4510 -u terraform -D terraform_practice -p
      2Enter password:
      3Welcome to the MariaDB monitor.  Commands end with ; or \g.
      4Your MariaDB connection id is 10
      5Server version: 10.5.19-MariaDB-0+deb11u2 Debian 11
      6
      7Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
      8
      9Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
    • テーブルを作成
      1MariaDB [terraform_practice]> CREATE TABLE practice (id INT, name VARCHAR(10), update_time DATETIME);
      2Query OK, 0 rows affected (0.022 sec)
    • データを挿入
      1MariaDB [terraform_practice]> INSERT INTO practice VALUES (1, "a", NOW()), (2, "b", NOW()), (3, "c", NOW());
      2Query OK, 3 rows affected (0.025 sec)
      3Records: 3  Duplicates: 0  Warnings: 0
    • 挿入したデータを確認
      1MariaDB [terraform_practice]> SELECT * FROM practice;
      2+------+------+---------------------+
      3| id   | name | update_time         |
      4+------+------+---------------------+
      5|    1 | a    | 2023-06-09 04:49:58 |
      6|    2 | b    | 2023-06-09 04:49:58 |
      7|    3 | c    | 2023-06-09 04:49:58 |
      8+------+------+---------------------+
      93 rows in set (0.001 sec)

    web-server設定

    • web-serverのコンテナーに入る
      1docker exec -it c9e63e3ae05b bash
    • インストール済みのプログラムを更新
      1apt-get update -y
    • 必要なプログラムやツールをインストール
      1apt-get install vim net-tools procps curl nginx -y
    • nginxがインストールされていることを確認
      1$ nginx -v
      2nginx version: nginx/1.18.0 (Ubuntu)
    • nginxを起動
      1nginx
    • nginxにアクセスできるかを確認
      • ホストマシンからcurlで確認
        1curl http://127.0.0.1/
      • dockerのコンテナー内からcurlで確認
        1curl http://172.17.0.3/
      • 出力は下記
        1<!DOCTYPE html>
        2<html>
        3<head>
        4<title>Welcome to nginx!</title>
        5<style>
        6    body {
        7        width: 35em;
        8        margin: 0 auto;
        9        font-family: Tahoma, Verdana, Arial, sans-serif;
        10    }
        11</style>
        12</head>
        13<body>
        14<h1>Welcome to nginx!</h1>
        15<p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p>
        16
        17<p>For online documentation and support please refer to
        18<a href="http://nginx.org/">nginx.org</a>.<br/>
        19Commercial support is available at
        20<a href="http://nginx.com/">nginx.com</a>.</p>
        21
        22<p><em>Thank you for using nginx.</em></p>
        23</body>
        24</html>
    • nginxの通信をすべてapp-serverに向くよう設定
      1$ vi / etc/nginx/sites-available/default
      /etc/nginx/sites-available/default
      1# before:
      2location / {
      3        # First attempt to serve request as file, then
      4        # as directory, then fall back to displaying a 404.
      5        try_files $uri $uri/ =404;
      6}
      7
      89
      10# after:
      11location / {
      12        # First attempt to serve request as file, then
      13        # as directory, then fall back to displaying a 404.
      14        # try_files $uri $uri/ =404;
      15        proxy_pass http://172.17.0.4:8080/;
      16}
    • nginxを再起動
      1nginx -s reload
    • リバースプロキシの設定反映されていることを確認
      • ホストマシンからcurlで確認
        1curl http://127.0.0.1/
      • dockerのコンテナー内からcurlで確認
        1curl http://172.17.0.3/
      • 出力は下記
        1<html>
        2<head><title>502 Bad Gateway</title></head>
        3<body>
        4<center><h1>502 Bad Gateway</h1></center>
        5<hr><center>nginx/1.18.0 (Ubuntu)</center>
        6</body>
        7</html>
      • ステータスコード502であれば正しく反映されている

    app-server設定

    • app-serverのコンテナーに入る
      1docker exec -it f16e0697c324 bash
    • インストール済みのプログラムを更新
      1apt-get update -y
    • 必要なプログラムやツールをインストール
      1apt-get install vim net-tools procps curl git golang-go -y
    • gitがインストールされていることを確認
      1$ git --version
      2git version 2.25.1
    • golangがインストールされていることを確認
      1$ go version
      2go version go1.13.8 linux/arm64
    • golangのMySQLのドライバーをインストール
      1go get -u github.com/go-sql-driver/mysql
    • スクリプトのディレクトリを作成
      1mkdir /root/src
    • スクリプトを作成
      1$ vi /root/src/main.go
      /root/src/main.go
      1package main
      2
      3import (
      4    "fmt"
      5    "strconv"
      6    "net/http"
      7    "database/sql"
      8
      9    _ "github.com/go-sql-driver/mysql"
      10)
      11
      12type PracticeDto struct {
      13    id          int
      14    name        string
      15    update_time string
      16}
      17
      18func getDataFromMysql(id int) PracticeDto {
      19    db, err := sql.Open("mysql", "terraform:terraform!@tcp(172.17.0.2:4510)/terraform_practice")
      20    if err != nil {
      21        panic(err.Error())
      22    }
      23    defer db.Close()
      24
      25    var dto PracticeDto
      26    err = db.QueryRow("SELECT * FROM practice WHERE id = ?", id).Scan(&dto.id, &dto.name, &dto.update_time)
      27    if err != nil {
      28        panic(err.Error())
      29    }
      30
      31    return dto
      32}
      33
      34func main() {
      35    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
      36        id, _ := strconv.Atoi(r.FormValue("id"))
      37		mysql_res := getDataFromMysql(id)
      38
      39        fmt.Fprintf(w, "Hello, you've requested: %s\n", r.URL.Path[1:])
      40		fmt.Fprintf(w, "Your requested id's (id: %d) result is [id: %d; name: %s; update_time: %s]\n", id, mysql_res.id, mysql_res.name, mysql_res.update_time)
      41    })
      42
      43    http.ListenAndServe(":8080", nil)
      44}
    • スクリプトファイルができたかを確認
      1$ ls -l /root/src
      2total 4
      3-rw-r--r-- 1 root root 1083 Jun  9 16:31 main.go
    • スクリプトをビルド
      1go build -o /root/src/main /root/src/main.go
    • ビルドしたファイルができたかを確認
      1ls -l /root/src/
      2total 7532
      3-rwxr-xr-x 1 root root 7815206 Jun  9 16:34 main
      4-rw-r--r-- 1 root root    1083 Jun  9 16:31 main.go
    • ビルドしたファイルを実行
      1/root/src/main
    • 動作確認
      • ホストマシンからcurlで確認
        1$ curl http://127.0.0.1:35709/dummy_uri\?id=1
      • dockerのコンテナー内からcurlで確認
        1curl http://172.17.0.4:8080/dummy_uri?id=1
      • 出力は下記
        1Hello, you've requested: dummy_uri
        2Your requested id's (id: 1) result is [id: 1; name: a; update_time: 2023-06-09 04:49:58]

    動作確認

    • ホストマシン → web-server → app-serverの経路で通信しているかを確認
      1$ curl http://127.0.0.1/test_uri\?id=2
      2Hello, you've requested: test_uri
      3Your requested id's (id: 2) result is [id: 2; name: b; update_time: 2023-06-09 04:49:58]
      • ホストマシン → web-server → app-server経路で通信していることが確認できた

    ライトコードでは、エンジニアを積極採用中!

    ライトコードでは、エンジニアを積極採用しています!社長と一杯しながらお話しする機会もご用意しております。そのほかカジュアル面談等もございますので、くわしくは採用情報をご確認ください。

    採用情報へ

    ハク(エンジニア)
    ハク(エンジニア)
    Show more...

    おすすめ記事

    エンジニア大募集中!

    ライトコードでは、エンジニアを積極採用中です。

    特に、WEBエンジニアとモバイルエンジニアは是非ご応募お待ちしております!

    また、フリーランスエンジニア様も大募集中です。

    background