ハク(エンジニア)
【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:41 │ 5│ 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
- 途中でプロンプトが出るので、planと同じ内容出ていたら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のコンテナーID
c9e63e3ae05b
とf16e0697c324
は立てられたEC2で、起動していることが確認できたc9e63e3ae05b
はweb-serverとしますf16e0697c324
はapp-serverとします
- dockerのコンテナーID
- 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... (中略) ...
- インスタンスID
i-0265072bfb2fbdc0a
とi-85a837419413c12d9
は起動していることが確認できた - IPアドレスとポート番号は必要なのでメモを取る
- インスタンスID
- dockerのコンテナーを確認
- RDS確認
- LocalStackのコンテナーに入る
- ↑の出力からコンテナーIDは
ed08d7441d54
1docker exec -it ed08d7441d54 bash
- ↑の出力からコンテナーIDは
- プロセス確認
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は起動していることが確認できた
- LocalStackのコンテナーに入る
- EC2確認
接続情報
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>
- ホストマシンからcurlで確認
- nginxの通信をすべてapp-serverに向くよう設定
/etc/nginx/sites-available/default
1$ vi / 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 8↓ 9 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であれば正しく反映されている
- ホストマシンから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がインストールされていることを確認
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
- スクリプトを作成
/root/src/main.go
1$ vi /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]
- ホストマシンからcurlで確認
動作確認
- ホストマシン → 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...お酒が友達のバックエンドエンジニアです。 インフラとお友達になりたい…。 最近暑いので水分補給と酔分補給を怠らないようにしましょう。