##ざっくりとやること・できることの説明
- docker-composeでNginxとGo言語のAPI, DBとしてMySQLのコンテナを3つ立ち上げる
- Nginxのindex.htmlからGo言語で書いたREST API(go-ginのフレームワーク使用)を経由して、DBに問い合わせ
- DBにCRUD(gormのフレームワーク使用)ができることを確認
- ※DockerとDocker Composeはインストールされているものとする。
##バージョン確認
確認してみたら、以下のバージョンでした。
Docker version 20.10.2
docker-compose version 1.27.4
golang:1.14.7-alpine3.12
mysql:5.7
nginx:1.17.3-alpine
※厳密にはバージョンの依存関係とかも考えないといけないが、一旦ローカルで動かすので、スルーしますm(__)m
#フォルダ構成
docker-local
├── .env
├── api
│ └── src
│ ├── main.go
│ ├── model ── model.go
│ └── config ── config.go
├── db
│ ├── conf ── my.cnf
│ └── db-data
├── docker
│ └── nginx
│ ├── Dockerfile
│ └── nginx.conf
├── docker-compose.yml
└── web
├── env
│ └── nginx ── site.conf
└ src ── index.html
###ディレクトリとファイルの用途解説
名前 | 種類 | 説明 |
---|---|---|
docker-local | フォルダ | dockerローカルアプリケーションの親フォルダ |
.env | ファイル | docker-composeで使う環境変数のファイル |
api | フォルダ | APIのフォルダ |
src | フォルダ | ソースフォルダ |
main.go | ファイル | goを起動するときのファイル |
model/model.go | ファイル | DBとやりとりする時のファイル struct, dao系のメソッドを記載 |
config/config.go | ファイル | DBの接続情報等を記載 |
db | フォルダ | DBに関するフォルダ |
conf/my.cnf | ファイル | 任意のDB設定を記載。マウント用 |
db-data | フォルダ | DBのデータをsyncするマウント用 |
docker | フォルダ | Dockerfileたちを格納するフォルダ |
nginx | フォルダ | NginxのimageをビルドするDockerfileを格納 |
Dockerfile | ファイル | nginxのimage |
nginx.conf | ファイル | nginxの設定ファイル |
docker-compose.yml | ファイル | docker containerを一括でコントロールするyamlファイル |
web | フォルダ | フロントのファイルを格納 |
env | フォルダ | 環境設定ファイルを格納 |
nginx/site.conf | ファイル | nginxのserver設定ファイル IPアドレス、ポート、ルーティングなど設定 |
src/index.html | ファイル | 画面表示用ファイル |
#Docker Composeの中身
version: "3.8"
services:
nginx:
image: infra-challenge:nginx-20210312
# command:
build:
context: ./docker/nginx
dockerfile: Dockerfile
container_name: nginx
ports:
- 80:80
volumes:
- ./web/env/nginx:/etc/nginx/conf.d
- ./web/src:/var/www/html
depends_on:
- api
logging:
driver: "none"
restart: always
networks:
- services
api:
image: golang:1.14.7-alpine3.12
command: go run main.go --host 0.0.0.0 --port 8080
container_name: api
ports:
- 8080:8080
volumes:
- ./api:/go/src/github.com/infra-challenge/api
- /Users/username/go:/go
working_dir: /go/src/github.com/infra-challenge/api/src
environment:
- APP_STAGE=local
- LOG_LEVEL=debug
- MYSQL_CONNECTION
depends_on:
- db
restart: always
networks:
- services
db:
image: mysql:5.7
# build: ./docker/mysql
container_name: db
ports:
- 3306:3306
volumes:
- ./db/conf/my.cnf:/etc/mysql/conf.d/my.cnf
- ./db/db-data:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD
- MYSQL_DATABASE
- MYSQL_USER
- MYSQL_PASSWORD
healthcheck:
test: ["CMD-SHELL", "mysqlshow -u ${MYSQL_USER} -p${MYSQL_PASSWORD}"]
interval: "5s"
retries: 10
logging:
driver: "none"
restart: always
networks:
- services
networks:
services:
external:
name: local_infra_challenge_networks
###主な属性の解説
-
docker compose
の文法バージョンは3.8
だよ -
services
配下に、コンテナの定義を書いていく。今回はnginx, api, dbの3つ -
nginx
はDockerfile
を使うから、image名は任意で、build
の属性を指定。-
context
はDockerfileのある相対パス、dockerfile
はDockerfile名 - ※ファイル名が
Dockerfile
となっていたら、build: ./docker/nginx
としてもOK
-
-
container_name
を指定すると、docker stop
とかするときに、idじゃなくて名前を指定すれば制御できるので便利 -
ports
は<ホスト(Macローカル)>:<ゲスト(Dockerコンテナ)>
でポートを接続 -
volumes
は<ホスト(Macローカル)>:<ゲスト(Dockerコンテナ)>
でマウントフォルダを指定- マウントとは、フォルダ同士を共有してsync(同期)すること。
-
depends_on
は他のコンテナが起動成功でき次第〜みたいなやつ - apiとdbは、自分でDockerfileは用意せずに、
Docker-Hub
公式のimageを使っている -
environment
に環境変数を指定する。-
docker-compose.yml
と同階層に.env
ファイルを置き指定
-
- DBでは
healthcheck
を行い、起動しているか随時確認 - ネットワークを組むことで、コンテナ間通信が可能となり、APIからDBに問い合わせができるようになった
###ネットワークについて
作ったネットワークの情報を確認してみると、下記のようなObjectが返ってきますね〜
"Subnet": "172.19.0.0/16",
の中で、Containers(nginx, api, db)がIPアドレスを振られて存在しているのがわかります。
ちなみに、networks
だけでなくlinks
という属性もあり、links
を使うと、一方的にコンテナ間通信ができるようになる設定もあるので、TPOによって使い分ける◎
公式docker:links
$ docker network inspect local_infra_challenge_networks
[
{
"Name": "local_infra_challenge_networks",
"Id": "f6a978e6f3aa803be061418c1c7081d132c9538c207ea08b1d732fc55ba2b917",
"Created": "2021-03-12T03:57:20.0697997Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.19.0.0/16",
"Gateway": "172.19.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"7a81d8c6f965a07ce446aa0983180bbb4775187ed6873a9e26dbc9540f623392": {
"Name": "nginx",
"EndpointID": "09336c1acc58f9b75ea3ced604a7d82b168a5f0cd132ae4f2fffd267a416b022",
"MacAddress": "02:42:ac:13:00:04",
"IPv4Address": "172.19.0.4/16", #<-これ!!
"IPv6Address": ""
},
"842244244bf00593e25317dd1cafb35ae03cfbc5246a87c666c6434a6ad7540d": {
"Name": "db",
"EndpointID": "3810c5b1b5f87b3ba4331320fcb2106696f3dcd157a771f9de63aeffc3a14720",
"MacAddress": "02:42:ac:13:00:02",
"IPv4Address": "172.19.0.2/16", #<-これ!!
"IPv6Address": ""
},
"c0906b3fc86d92f4b89474b7647e85a36e489469f83905c94785f2f278807532": {
"Name": "api",
"EndpointID": "e291176e7bd08040c2486d0409dab009a724fb7e3f0da3a5a9585cb23344a999",
"MacAddress": "02:42:ac:13:00:03",
"IPv4Address": "172.19.0.3/16", #<-これ!!
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
]
####コンテナ間通信をするときは、コンテナ名でエンドポイントを指定することができるから便利
# db:3306 の部分 <コンテナ名:ポート>
MYSQL_CONNECTION=local:local@tcp(db:3306)/infra-challenge
###マウントについて
####nginx
volumes:
- ./web/env/nginx:/etc/nginx/conf.d
- ./web/src:/var/www/html
- nginxには
default.conf
というものがあり、それを自分の設定に書き換えたいので、./web/env/nginx
で書き換えてる -
/var/www/html
以下がdockerコンテナ内のnginxフォルダ構成になる(する)ので、index.htmlがあるディレクトリを同期
####api
volumes:
- ./api:/go/src/github.com/infra-challenge/api
- /Users/username/go:/go
- とりあえずGo Pathが通っているところをdockerコンテナ側にマウントしてる。
- APIのファイル等も同期
####db
volumes:
- ./db/conf/my.cnf:/etc/mysql/conf.d/my.cnf
- ./db/db-data:/var/lib/mysql
- MySQLのデータの格納先が
/var/lib/mysql
になるので、ホストの./db/db-data
に同期して、コンテナを除去してもデータが消えないようにする - 自分のDB設定、例えば、
character-set
とかcollation
とかをマウントして上書き
# my.cnf
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
[mysql]
default-character-set=utf8mb4
#いざ、Docker Composeで起動してみる!!
##コマンド
$ cd /Users/username/src/github.com/infra-challege/docker-local
$ docker network create --driver bridge local_infra_challenge_networks
[~省略~]
$ docker-compose build --no-cache
[~省略~]
$ docker-compose up -d --remove-orphans
Creating db ... done
Creating api ... done
Creating nginx ... done
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8fxxxb102ed4 infra-challenge:nginx-20210312 "nginx -g 'daemon of…" 4 seconds ago Up 3 seconds 0.0.0.0:80->80/tcp nginx
8fxxx25640e6 golang:1.14.7-alpine3.12 "go run main.go --ho…" 6 seconds ago Up 4 seconds 0.0.0.0:8080->8080/tcp api
e5xxxe97320e mysql:5.7 "docker-entrypoint.s…" 6 seconds ago Up 5 seconds (health: starting) 0.0.0.0:3306->3306/tcp, 33060/tcp db
- docker-composeファイルがある階層に移動
-
networks
属性を指定したので、そのネットワークを作成する。 - nginxはDockerfileをつかってimageを作成するので、ビルドする必要がある。
-
--no-cache
オプション:構築時にイメージのキャッシュを使わない。
-
- docker-compose upで起動
-
-d
オプション:バックグラウンド実行 -
--remove-orphans
オプション:Composeファイルで定義されていないサービス用のコンテナを削除
-
#Webページにアクセスできるか確認
(超しょぼいですが...w)
アクセスできた!
##コンテナ終了コマンド
$ docker-compose down
Stopping nginx ... done
Stopping api ... done
Stopping db ... done
Removing nginx ... done
Removing api ... done
Removing db ... done
止まりました。
#ハマったポイント
-
go run main.go
した後に、起動はしていたがポート設定がミスっていて、APIにアクセスできなかった。- 「なんかうまくいかないな〜〜汗」ってなったので、VSCodeから一旦APIサーバーを止めて再起動して、通信がうまくいったけど、それはコンテナ間通信ではなかった、、、
- コンテナ上ではなくローカルでAPIサーバーが立ち上がってしまい、通信できていると勘違いしてしまった。
- 「なんかうまくいかないな〜〜汗」ってなったので、VSCodeから一旦APIサーバーを止めて再起動して、通信がうまくいったけど、それはコンテナ間通信ではなかった、、、
-
index.html
の画面表示するポートとAPI
を司るポートそれぞれが別だったので、その調整にハマった。 - nginxには、サーバー設定が必要だった。
-
nginx.conf
とdefault.conf
というファイルが存在しこれのIPアドレス、ポート等を設定しないといけないので、前もってnginxの知識をいれておかないと簡単には動かなかった
-
# site.conf (default.confの上書き)
server {
listen 80;
listen 8080; # APIで8080ポートも使ってる関係で、これも必要だった
server_name localhost;
root /var/www/html;
location / {
index index.html index.htm;
root /var/www/html;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /var/www/html/error;
}
}
#まとめ
docker-compose.ymlでコンテナを起動して、Dockerアプリケーションを作る感覚がつかめたので、楽しかったですわい!
コンテナのコントロールってすごい簡単で、サクサク動くから、せっかちな自分でも全然苦じゃない。
マスターしていきたいなああああ
以上、ありがとうございました!