docker-composeで勉強用のgolang環境を作ってみる

# 目的
Windows上でgolang勉強用の環境を作成します。
golangだけでなく、DBも利用したいのでPostgrSQL環境も合わせて作成します。

# 環境
- ホスト
    - Windows 10 Pro 64bit
    - Docker for Windows(Docker Desktop Community) 2.0.0.3
        - Docker Engine 18.09.2
        - Compose 1.23.2
- コンテナイメージ
    - CentOS:7
        - golang 1.12.4
        - vim latest
    - PostgreSQL:latest

# 作成
## Dockerfile(golang用)
Dockerfileで実行しようとしていることは、タイムゾーンの設定とyumのアップデート等、最新vimのインストール、golangのインストール、ホストとの共有用ディレクトリの作成(/share)です。

yumのアップデートやパッケージのインストールは、普通にやろうと失敗するので、先に`rpm --rebuilddb`でRPM DBを修復します。
[参考:Docker - Rpmdb checksum is invalid: dCDPT(pkg checksums): xxxx.amzn1 — u 対処法](https://medium.com/@fkei/docker-rpmdb-checksum-is-invalid-dcdpt-pkg-checksums-xxxx-amzn1-u-%E5%AF%BE%E5%87%A6%E6%B3%95-289b8c58d4a3)

最終行の`CMD [ "/sbin/init" ]`は、このコンテナ上で起動するプロセス(dockerがコンテナ監視するプロセス？)です。このプロセスをコンテナ起動後にkillするとコンテナは瞬断しますし、逆にこの行がないとそもそも起動しません。

vimは個人的に使うので入れていますが、不要であれば削除しても問題ないです。
/shareが、ホストと共有できるディレクトリなので、ホストでプログラム等を作成して送ることもできるので。
\# もちろん`docker cp`でできるから、共有用はいらないのであれば、/shareも削除しても問題ないです。

```yaml
FROM centos:7
LABEL maintainer "@hirano00o"

ENV GO_INSTALL_DIR /usr/local
ENV HOME /root
ENV GO_VERSION 1.12.4

# set timezone
RUN ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime

# compile and install vim
RUN rpm --rebuilddb && yum update -y && \
    yum -y install git gcc ncurses-devel make && \
    yum -y install httpd which && \
    rm -rf /var/cache/yum/* && \
    yum clean all

WORKDIR /usr/local/src/
RUN git clone https://github.com/vim/vim.git && \
    cd vim && \
    make && make install && make clean && \
    rm -rf vim

# Your .vimrc
# ADD .vimrc ~/

# get golang and set $GOPATH
WORKDIR ${GO_INSTALL_DIR}
RUN curl https://dl.google.com/go/go${GO_VERSION}.linux-amd64.tar.gz > go.tar.gz && \
    tar zxf go.tar.gz && \
    rm go.tar.gz

WORKDIR ${HOME}
RUN echo 'export GOROOT=/usr/local/go' >> ${HOME}/.bashrc
RUN echo 'export GOPATH=${HOME}/go' >> ${HOME}/.bashrc
RUN echo 'export PATH=${GOROOT}/bin:${PATH}' >> ${HOME}/.bashrc
RUN mkdir -p ${HOME}/go/src

# make directory to share with host
RUN mkdir -p /share

CMD [ "/sbin/init" ]
```
## Dockerfile(postgres用)
postgresqlイメージのデフォルトは、当然LANGやTIMEZONEはus、UTCなので、Dockerfileで設定しておきます。
[参考:Docker Hub公式PostgreSQLで初期化ずみデータベースコンテナを作る
](https://qiita.com/hirosemi/items/199a3c753130c12d52f1)

`.sql`ファイルを/docker-entrypoint-initdb.d/に置いておくと、コンテナ起動時に自動的に実行してくれます。
とりあえずユーザやテスト用DB作成のsqlファイルを/sqlに作成しておきます。

```yaml
FROM postgres:latest
LABEL maintainer "@hirano00o"

# set timezone
RUN localedef -i ja_JP -c -f UTF-8 -A /usr/share/locale/locale.alias ja_JP.UTF-8
ENV LANG ja_JP.utf8

ADD sql/* /docker-entrypoint-initdb.d/
```

## docker-compose.ymlの作成
`build`には、各々のDockerfileを格納しているディレクトリ名を指定しておきます。
また、postgersの/var/lib/postgresql配下は、作成したDBを保持しておきたいためホストと共有、golang側もホストとのファイル共有用に/shareをvolumesに指定しておきます。

golangからpostgresへは、サービス名(postgres)でアクセスしたいので、golangの`depends_on`にpostgresを指定します。

あとApacheを利用するかもしれないので、ホストの8080ポートとコンテナ内の80ポートをつなげておきます。
これくらいしておけば、大体のことはできるでしょう。

```yaml
version: "3"
services:
  postgres:
    restart: always
    build: postgres
    container_name: postgres
    volumes:
      - db_data:/var/lib/postgresql
    ports:
      - 5432:5432
  golang:
    build: golang
    container_name: golang
    privileged: true
    depends_on:
      - postgres
    volumes:
      - host_share:/share
    ports:
      - 8080:80
volumes:
  host_share:
    driver: local
    driver_opts:
      type: none
      device: /c/golang-container/share
      o: bind
  db_data:
    driver: local
    driver_opts:
      type: none
      device: /c/golang-container/db
      o: bind
```
`device`で指定したディレクトリは、ホスト上のディレクトリですが、コンテナ作成前に予め作成しておかないとエラーとなります。

```bash
Creating postgres ... error

ERROR: for postgres  Cannot create container for service postgres: error while mounting volume with options: type='none' device='/c/golang-container/db' o='bind': no such file or directory

ERROR: for postgres  Cannot create container for service postgres: error while mounting volume with options: type='none' device='/c/golang-container/db' o='bind': no such file or directory
ERROR: Encountered errors while bringing up the project.
```

# 実行
実行は、Windowsなので、コマンドプロントかPowerShell上で実行。(下記PowerShell上で実行)
vimのコンパイルが結構時間かかります。

```bash
PS C:\golang-container> docker-compose up -d
～省略～
PS C:\golang-container> docker ps
CONTAINER ID        IMAGE                       COMMAND                  CREATED              STATUS              PORTS                    NAMES
0480e929da66        golang-container_golang     "/sbin/init"             About a minute ago   Up About a minute   0.0.0.0:8080->80/tcp     golang
cc4d612168ad        golang-container_postgres   "docker-entrypoint.s…"   About a minute ago   Up About a minute   0.0.0.0:5432->5432/tcp   postgres

PS C:\golang-container> docker exec -it golang bash
[root@0480e929da66 ~]# go version
go version go1.12.4 linux/amd64
```

Apacheを使うなら、コンテナログインしていつもどおりのコマンドで実行。

```bash
PS C:\golang-container> docker exec -it golang bash
[root@0480e929da66 ~]# systemctl start httpd
```
コンテナを削除する場合は、upの反対を実行。

```bash
PS C:\golang-container> docker-compose down
Stopping golang   ... done
Stopping postgres ... done
Removing golang   ... done
Removing postgres ... done
Removing network golang-container_default
```

### 余談
コンテナ上で動いているプロセスはこんな感じです。

```bash
[root@0480e929da66 ~]# ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 00:45 ?        00:00:00 /sbin/init
root        24     1  0 00:45 ?        00:00:00 /usr/lib/systemd/systemd-journald
root        26     1  0 00:45 ?        00:00:00 /usr/lib/systemd/systemd-udevd
root       124     1  0 00:45 ?        00:00:00 /usr/lib/systemd/systemd-logind
dbus       125     1  0 00:45 ?        00:00:00 /usr/bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --root       192     1  0 00:45 tty1     00:00:00 /sbin/agetty --noclear tty1 linux
root      1970     0  0 00:51 pts/0    00:00:00 bash
root      1987     1  0 00:51 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache    1988  1987  0 00:51 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache    1989  1987  0 00:51 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache    1990  1987  0 00:51 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache    1991  1987  0 00:51 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache    1992  1987  0 00:51 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
root      1994  1970  0 00:56 pts/0    00:00:00 ps -ef
```
`/sbin/init`をkillしてみます。

```bash
[root@0480e929da66 ~]# kill -9 0
PS C:\golang-container> docker ps
CONTAINER ID        IMAGE                       COMMAND                  CREATED             STATUS              PORTS                    NAMES
0480e929da66        golang-container_golang     "/sbin/init"             13 minutes ago      Up 13 minutes       0.0.0.0:8080->80/tcp     golang
cc4d612168ad        golang-container_postgres   "docker-entrypoint.s…"   13 minutes ago      Up 13 minutes       0.0.0.0:5432->5432/tcp   postgres
```
一瞬で再起動したようですね。もう一度コンテナログインして確認しましたが、何も変わってないように見えます。。。

```bash
PS C:\golang-container> docker exec -it golang bash
[root@0480e929da66 ~]# ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 00:45 ?        00:00:00 /sbin/init
root        24     1  0 00:45 ?        00:00:00 /usr/lib/systemd/systemd-journald
root        26     1  0 00:45 ?        00:00:00 /usr/lib/systemd/systemd-udevd
root       124     1  0 00:45 ?        00:00:00 /usr/lib/systemd/systemd-logind
dbus       125     1  0 00:45 ?        00:00:00 /usr/bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --syst
root       192     1  0 00:45 tty1     00:00:00 /sbin/agetty --noclear tty1 linux
root      1987     1  0 00:51 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache    1988  1987  0 00:51 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache    1989  1987  0 00:51 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache    1990  1987  0 00:51 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache    1991  1987  0 00:51 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache    1992  1987  0 00:51 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
root      2029     0  0 00:59 pts/0    00:00:00 bash
root      2042  2029  0 00:59 pts/0    00:00:00 ps -ef
```

# 最後に
今回のファイル等は、[hirano00o/golang-devenv-docker](https://github.com/hirano00o/golang-devenv-docker)で公開しています。
コンテナは、いろいろ試したいけど環境汚したくないとき等に非常に便利ですね。