
【macOS】LocalStack+terraformでEC2+RDSを立ててみた
2023.06.19
注意
- 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がインストールされていることを確認
12$ localstack --version2.1.0 - LocalStack Pro版のAPIキーを環境変数に登録
1export LOCALSTACK_API_KEY=xxxxxxxxxx - LocalStackを起動
1234567891011121314151617$ localstack start -d__ _______ __ __/ / ____ _________ _/ / ___// /_____ ______/ /__/ / / __ \/ ___/ __ `/ /\__ \/ __/ __ `/ ___/ //_// /___/ /_/ / /__/ /_/ / /___/ / /_/ /_/ / /__/ ,</_____/\____/\___/\__,_/_//____/\__/\__,_/\___/_/|_|💻 LocalStack CLI 2.1.0[10:41:13] starting LocalStack in Docker mode 🐳 localstack.py:1422023-06-09T10:41:15.565 INFO --- [ MainThread] l.bootstrap.licensing : Successfully activated API key2023-06-09T10:41:15.880 INFO --- [ MainThread] localstack.utils.bootstrap : Execution of "prepare_host" took 1896.32ms[10:41:15] preparing environment bootstrap.py:630[10:41:16] configuring container bootstrap.py:638[10:41:17] starting container bootstrap.py:645[10:41:18] detaching bootstrap.py:649 - LocalStackが起動していることを確認
12345678910$ localstack status┌─────────────────┬───────────────────────────────────────────────────────┐│ Runtime version │ 2.1.1.dev ││ Docker image │ tag: latest, id: 9ff2ae7ae1a0, 📆 2023-06-02T11:46:41 ││ Runtime status │ ✔ running (name: "localstack_main", IP: 172.17.0.2) │└─────────────────┴───────────────────────────────────────────────────────┘$ docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES5f55c6aea975 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がインストールされていることを確認
1234567$ terraform versionTerraform v1.4.6on darwin_arm64+ provider registry.terraform.io/hashicorp/aws v5.1.0+ provider registry.terraform.io/hashicorp/http v3.3.0+ provider registry.terraform.io/hashicorp/local v2.4.0+ 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されていることを確認
12345$ docker imagesREPOSITORY TAG IMAGE ID CREATED SIZE... (中略) ...ubuntu focal 758cd4ebb217 8 weeks ago 65.7MB... (中略) ... - LocalStack用のtagを追加
1docker tag ubuntu:focal localstack-ec2/ubuntu-focal-ami:ami-000001 - tagが追加されたことを確認
123456$ docker imagesREPOSITORY TAG IMAGE ID CREATED SIZE... (中略) ...localstack-ec2/ubuntu-focal-ami ami-000001 758cd4ebb217 8 weeks ago 65.7MBubuntu focal 758cd4ebb217 8 weeks ago 65.7MB... (中略) ...
AWSプロフィールを設定
- aws-cliで設定
- AWS Access Key ID: dummy
- AWS Secret Access Key: dummy
- Default region name: ap-northeast-1
- Default output format: json
12345$ aws configure --profile localstackAWS Access Key ID [None]: dummyAWS Secret Access Key [None]: dummyDefault region name [None]: ap-northeast-1Default output format [None]: json - AWSプロフィールが設定されていることを確認
1234567$ aws configure list --profile localstackName Value Type Location---- ----- ---- --------profile localstack manual --profileaccess_key ****************ummy shared-credentials-filesecret_key ****************ummy shared-credentials-fileregion ap-northeast-1 config-file ~/.aws/config
サーバー構成図
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
+----------------------------------------------+ | +--------------------------------+ | | | RDS | | | | (MySQL) | <---+ | | | port: determined by LocalStack | | | | +--------------------------------+ | | | | | | | | | | | | +------------+ +------------+ | | | web-server | | app-server | | | | (nginx) | -------------> | (golang) | | | | port: 80 | | port: 8080 | | | +------------+ +------------+ | +----------------------------------------------+ |
- RDS: LocalStackのコンテナー内にMySQLが起動する
- web-server: 一つのdockerコンテナーとして作られる
- web-serverの役割は通信の出入りで、リクエストが来たらapp-serverに通す(リバースプロキシ)
- app-server: 一つのdockerコンテナーとして作られる
- リクエストのIDをMySQLに格納されているデータを取得し、その結果を返却するプログラム
terraformでEC2とRDSを構築
- ディレクトリ構図
123456789101112131415.├── main.tf├── output.tf├── provider.tf├── ec2│ ├── keypair.tf│ ├── main.tf│ ├── output.tf│ └── variables.tf├── rds│ ├── main.tf│ └── variables.tf└── vpc├── main.tf└── output.tf- 上記のファイルはgit(url)に上げています
- initとplanをします
12$ terraform init$ terraform plan - 内容を確認したらapplyを実行します
1$ terraform apply- 途中でプロンプトが出るので、planと同じ内容出ていたらyesを打ちます
12345Do you want to perform these actions?Terraform will perform the actions described above.Only 'yes' will be accepted to approve.Enter a value: yes
- 途中でプロンプトが出るので、planと同じ内容出ていたらyesを打ちます
- EC2とRDSが起動していることを確認
- EC2確認
- dockerのコンテナーを確認
12345$ docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMESf16e0697c324 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-85a837419413c12d9c9e63e3ae05b 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-0265072bfb2fbdc0aed08d7441d54 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のコンテナーID
c9e63e3ae05b
とf16e0697c324
は立てられたEC2で、起動していることが確認できたc9e63e3ae05b
はweb-serverとしますf16e0697c324
はapp-serverとします
- dockerのコンテナーID
- LocalStackのログを確認
123456789$ localstack logs... (中略) ...2023-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:222023-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}2023-06-09T03:59:02.398 INFO --- [ asgi_gw_4] localstack.request.aws : AWS ec2.RunInstances => 2002023-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:222023-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}2023-06-09T03:59:02.492 INFO --- [ asgi_gw_0] localstack.request.aws : AWS ec2.RunInstances => 200... (中略) ...- インスタンスID
i-0265072bfb2fbdc0a
とi-85a837419413c12d9
は起動していることが確認できた - IPアドレスとポート番号は必要なのでメモを取る
- インスタンスID
- dockerのコンテナーを確認
- RDS確認
- LocalStackのコンテナーに入る
- ↑の出力からコンテナーIDは
ed08d7441d54
1docker exec -it ed08d7441d54 bash - ↑の出力からコンテナーIDは
- プロセス確認
12345678root@ed08d7441d54:/opt/code/localstack# ps auxUSER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMANDroot 1 0.0 0.1 11372 8628 ? Ss 03:56 0:00 /opt/code/localroot 15 0.4 4.4 1921908 359844 ? Sl 03:56 0:07 /opt/code/localroot 1354 0.0 0.0 2056 464 ? Ss 03:58 0:00 /bin/sh -c mysqmysql 1355 0.0 0.9 1418084 80080 ? Sl 03:58 0:00 mysqld --no-defroot 3710 0.5 0.0 5844 3452 pts/0 Ss 04:28 0:00 bashroot 3716 0.0 0.0 8340 2840 pts/0 R+ 04:28 0:00 ps aux
- ポート番号はLocalStackのログで確認
1234$ localstack logs | grep rds... (中略) ...2023-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"... (中略) ...
- ポート番号は4510であることがわかりました
- MySQLは起動していることが確認できた
- LocalStackのコンテナーに入る
- EC2確認
接続情報
1 2 3 4 |
type docker-container-id ip-address port ec2 (web-server) c9e63e3ae05b 172.17.0.3 80->80; 8080->8080 ec2 (app-server) f16e0697c324 172.17.0.4 60385->80; 35709->8080 rds ed08d7441d54 172.17.0.2 4510 |
RDSデータ準備
- MySQLにログイン
123456789root@ed08d7441d54:/opt/code/localstack# mysql -h 127.0.0.1 -P 4510 -u terraform -D terraform_practice -pEnter password:Welcome to the MariaDB monitor. Commands end with ; or \g.Your MariaDB connection id is 10Server version: 10.5.19-MariaDB-0+deb11u2 Debian 11Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. - テーブルを作成
12MariaDB [terraform_practice]> CREATE TABLE practice (id INT, name VARCHAR(10), update_time DATETIME);Query OK, 0 rows affected (0.022 sec) - データを挿入
123MariaDB [terraform_practice]> INSERT INTO practice VALUES (1, "a", NOW()), (2, "b", NOW()), (3, "c", NOW());Query OK, 3 rows affected (0.025 sec)Records: 3 Duplicates: 0 Warnings: 0 - 挿入したデータを確認
123456789MariaDB [terraform_practice]> SELECT * FROM practice;+------+------+---------------------+| id | name | update_time |+------+------+---------------------+| 1 | a | 2023-06-09 04:49:58 || 2 | b | 2023-06-09 04:49:58 || 3 | c | 2023-06-09 04:49:58 |+------+------+---------------------+3 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がインストールされていることを確認
12$ nginx -vnginx version: nginx/1.18.0 (Ubuntu) - nginxを起動
1nginx - nginxにアクセスできるかを確認
- ホストマシンからcurlで確認
1curl http://127.0.0.1/ - dockerのコンテナー内からcurlで確認
1curl http://172.17.0.3/ - 出力は下記
123456789101112131415161718192021222324<!DOCTYPE html><html><head><title>Welcome to nginx!</title><style>body {width: 35em;margin: 0 auto;font-family: Tahoma, Verdana, Arial, sans-serif;}</style></head><body><h1>Welcome to nginx!</h1><p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p><p>For online documentation and support please refer to<a href="http://nginx.org/">nginx.org</a>.<br/>Commercial support is available at<a href="http://nginx.com/">nginx.com</a>.</p><p><em>Thank you for using nginx.</em></p></body></html>
- ホストマシンからcurlで確認
- nginxの通信をすべてapp-serverに向くよう設定
1$ vi / etc/nginx/sites-available/default
/etc/nginx/sites-available/default
12345678910111213141516# before:location / {# First attempt to serve request as file, then# as directory, then fall back to displaying a 404.try_files $uri $uri/ =404;}↓# after:location / {# First attempt to serve request as file, then# as directory, then fall back to displaying a 404.# try_files $uri $uri/ =404;proxy_pass http://172.17.0.4:8080/;} - nginxを再起動
1nginx -s reload - リバースプロキシの設定反映されていることを確認
- ホストマシンからcurlで確認
1curl http://127.0.0.1/ - dockerのコンテナー内からcurlで確認
1curl http://172.17.0.3/ - 出力は下記
1234567<html><head><title>502 Bad Gateway</title></head><body><center><h1>502 Bad Gateway</h1></center><hr><center>nginx/1.18.0 (Ubuntu)</center></body></html> - ステータスコード502であれば正しく反映されている
- ホストマシンからcurlで確認
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がインストールされていることを確認
12$ git --versiongit version 2.25.1 - golangがインストールされていることを確認
12$ go versiongo 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
1234567891011121314151617181920212223242526272829303132333435363738394041424344package mainimport ("fmt""strconv""net/http""database/sql"_ "github.com/go-sql-driver/mysql")type PracticeDto struct {id intname stringupdate_time string}func getDataFromMysql(id int) PracticeDto {db, err := sql.Open("mysql", "terraform:terraform!@tcp(172.17.0.2:4510)/terraform_practice")if err != nil {panic(err.Error())}defer db.Close()var dto PracticeDtoerr = db.QueryRow("SELECT * FROM practice WHERE id = ?", id).Scan(&dto.id, &dto.name, &dto.update_time)if err != nil {panic(err.Error())}return dto}func main() {http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {id, _ := strconv.Atoi(r.FormValue("id"))mysql_res := getDataFromMysql(id)fmt.Fprintf(w, "Hello, you've requested: %s\n", r.URL.Path[1:])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)})http.ListenAndServe(":8080", nil)} - スクリプトファイルができたかを確認
123$ ls -l /root/srctotal 4-rw-r--r-- 1 root root 1083 Jun 9 16:31 main.go - スクリプトをビルド
1go build -o /root/src/main /root/src/main.go - ビルドしたファイルができたかを確認
1234ls -l /root/src/total 7532-rwxr-xr-x 1 root root 7815206 Jun 9 16:34 main-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 - 出力は下記
12Hello, you've requested: dummy_uriYour requested id's (id: 1) result is [id: 1; name: a; update_time: 2023-06-09 04:49:58]
- ホストマシンからcurlで確認
動作確認
- ホストマシン → web-server → app-serverの経路で通信しているかを確認
123$ curl http://127.0.0.1/test_uri\?id=2Hello, you've requested: test_uriYour requested id's (id: 2) result is [id: 2; name: b; update_time: 2023-06-09 04:49:58]- ホストマシン → web-server → app-server経路で通信していることが確認できた
書いた人はこんな人

-
お酒が友達のバックエンドエンジニアです。
インフラとお友達になりたい…。
最近暑いので水分補給と酔分補給を怠らないようにしましょう。
IT技術7月 12, 2023GitHub CopilotとChatGPTでGoogle for Jobsの求人情報を作ってみた
IT技術7月 10, 2023GitHub Copilotを使ってみた
IT技術6月 16, 2023【macOS】LocalStack+terraformでEC2+RDSを立ててみた