最終目的
go言語でWebアプリを構築するためのgo開発環境をDockerで作成する。
目標
- Docker上にコンソール立ち上げ環境を作る。 ← 今ここ
- フレームワークginを使った簡単なREST APIサーバーを立ち上げる。
- イメージビルド時にプログラムをコンパイルしコンテナ起動と同時にホストPCからAPIにアクセスできるようにする。
goの選定
現在(2022/06/04)、最新のgoは1.18.3。
1.17と1.18で大きな仕様変更(Genericsの導入、Fuzzingが標準機能)あり。今までのアップグレードに比べて最大の変更ではないか?
Genericsは1.19で正式になり、1.18では試験的実装とのこと。
安定している1.17にしようかと思っていたが、勉強のためなので最新の1.18にして、Genericsを使用し始めよう。
なので、1.18系とする。
dockerイメージの選定
クラウド上にDeployすることを考えると、linux環境になる。destributionを考える。開発中にいろいろやりたいとするとubuntu。
ubuntuのLTSベースとしたかったが、ubuntuベースのgolangイメージなし...
DebianはイメージがあるのでDebianにする。
DebianのCurrent LTSはStretchだが、6/30で切れる...
次は、Debian 10 “Buster” で2024年6月まで。busterにしよう。
golangのバージョンは固定にして、必要なタイミングでマイナー(3桁目)をアップグレードしよう。
イメージは、1.18.3-buster
とする。
イメージ落としたらサイズがでかい。Deployの環境はalpineにするか別途検討。
Dokerfileの作成
クラウドにDeployする時のDockerfileと開発環境用のDockerfileは分けたい。
make
コマンドで立ち上げができるようにenvディレクトリにDockerfileをまとめる。
./
+ env/
+ Dockerfile.golang.dev
env/Dockerfile.golang.dev
作成
FROM golang:1.18.3-buster
試しにDockerイメージ作成、bash
を立ち上げてみて、環境を確認。
$ docker build -f env/Dockerfile.golang.dev -t dev-env-golang:latest .
$ docker run --rm -it golang-dev bash
root@48a707dd66d1:/go# uname -a
Linux 48a707dd66d1 5.10.102.1-microsoft-standard-WSL2 #1 SMP Wed Mar 2 00:30:59 UTC 2022 x86_64 GNU/Linux
root@48a707dd66d1:/go# cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 10 (buster)"
NAME="Debian GNU/Linux"
VERSION_ID="10"
VERSION="10 (buster)"
VERSION_CODENAME=buster
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"
root@48a707dd66d1:/go# hostname
48a707dd66d1
root@48a707dd66d1:/go# ip -4 address
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
15: eth0@if16: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link-netnsid 0
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
root@48a707dd66d1:/go# ip -4 route
default via 172.17.0.1 dev eth0
172.17.0.0/16 dev eth0 proto kernel scope link src 172.17.0.2
root@48a707dd66d1:/go# go version
go version go1.18.3 linux/amd64
- goは1.18.3
- distributionはDebian 10 buster
- rootでアクセス
- ホスト名、IPアドレスは
docker run
ごとに変わる - ネットワークIPはdocker設定のIP(作業者で異なる可能性)
rootアクセスはやめたい、ホスト環境のディレクトリをコンテナ環境のホームディレクトリに割り当てたい、ネットワークアドレスを指定したい、立ち上げをmakeコマンドで実施したい。
docker-composeとMakefileで制御することにする。
docker-compose環境の作成
方針
- ネットワークアドレスを指定したい
- rootアクセスはやめて
gouser
ユーザーアクセス -
src/golang
ディレクトリをコンテナ環境の/home/gouser
に割り当てる - 環境設定はファイルで設定(環境設定はコード管理しない)
- makeコマンドでいろいろ操作(長いコマンド打ちたくない)
構成は下記
./
+ env/
| + Dockerfile.golang.dev
+ src/
| + golang/
| + <home dir>
+ docker-compose.dev.yml
+ Makefile
+ .env # 環境変数(コード管理外)
+ .env.dev # コンテナ実行時の共通環境変数
ネットワークIPを固定化
dockerコマンドでコンテナが使用するネットワークdev-env-link
を作成する。
- コンテナからinternetにアクセスできる
- ネットワークアドレスは
192.168.10.0/24
- gatewayは
192.168.10.254
(コンテナのIPは1から振りたい)
docker-compose環境を複数立てたときに同一ネットワーク環境に同居させたいので、docker-compose.ymlでネットワークを定義しない。
$ docker network create --driver=bridge \
--subnet=192.168.10.0/24 \
--gateway=192.168.10.254 \
env-link
ネットワーク削除は下記
docker network remove dev-env-link
コマンド類は後でMakefileで定義する。
docker-compose.dev.ymlの作成
開発環境の各種設定は.env
ファイルで管理して、docker-compose.ymlで読み込み、Dockerイメージ作成時に継承させる。
.env
ファイルはコード管理外にする。
NETWORK_BASE=192.168.10
NETWORK_ADDR=192.168.10.0/24
NETWORK_GATEWAY_IP=192.168.10.254
TZ=Asia/Tokyo
USER_NAME=gouser
USER_ID=1000
GROUP_NAME=gouser
GROUP_ID=1000
コード管理してよい環境変数設定は.env.dev
で管理する。
LANGUAGE=C
LANG=C.UTF-8
LC_ALL=C.UTF-8
docker-compose.dev.ymlを作成
version: "3"
services:
golang:
build:
context: .
dockerfile: ./env/Dockerfile.golang.dev
args:
- USER_NAME=$USER_NAME
# - USER_PW=$USER_PW # いらない
- USER_ID=$USER_ID
- GROUP_NAME=$GROUP_NAME
- GROUP_ID=$GROUP_ID
- TZ=$TZ
image: dev-env-golang-image
container_name: dev-env-golang
command: bash
tty: true
volumes:
- ./src/golang:/home/$USER_NAME
env_file: .env.dev
environment:
- GO111MODULE=on
networks:
dev-env-link:
ipv4_address: $NETWORK_BASE.1 # .envのNETWORK_BASEと合わせて、コンテナのIPは192.168.10.1になる
networks:
dev-env-link:
external: true
Dockerfaleの書き換え
docker-compose.ymlからの環境変数を使用して以下の設定を行うように書き換える。
- logaletimeの設定
- システムユーザーの作成
FROM golang:1.18.3-buster
ARG USER_NAME=$USER_NAME
ARG USER_ID=$USER_ID
ARG GROUP_NAME=$GROUP_NAME
ARG GROUP_ID=$GROUP_ID
# ARG USER_PW=$USER_PW # いらない
ARG TZ=$TZ
ENV TZ=$TZ
RUN ln -sf /usr/share/zoneinfo/$TZ /etc/localtime
ENV DEBIAN_FRONTEND=noninteractive
RUN apt update && apt install -y sudo
RUN groupadd -g $GROUP_ID $GROUP_NAME && \
useradd -s /bin/bash -u $USER_ID -g $GROUP_ID -G sudo $USER_NAME -r -d /home/$USER_NAME -M && \
# パスワード設定いらない
# echo $USER_NAME:$USER_PW | chpasswd && \
echo "$USER_NAME ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
USER $USER_NAME
WORKDIR /home/$USER_NAME
docker-composeでbuild、up、execを実施。runで立ち上げないのは、stopでコンテナを止めたい、同一コンテナ上で複数のコンソールを立ち上げたいため。
$ docker-compose -f docker-compose.dev.yml build --force golang
$ docker-compose -f docker-compose.dev.yml up -d golang
Creating dev-env-golang ... done
$ docker-compose -f docker-compose.dev.yml exec golang bash
gouser@e0dd620928c2:~$
gouser@e0dd620928c2:~$ ip -4 address
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
173: eth0@if174: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link-netnsid 0
inet 192.168.10.1/24 brd 192.168.10.255 scope global eth0
valid_lft forever preferred_lft forever
gouser@e0dd620928c2:~$ ip -4 route
default via 192.168.10.254 dev eth0
192.168.10.0/24 dev eth0 proto kernel scope link src 192.168.10.1
gouser@e0dd620928c2:~$ grep gouser /etc/passwd
gouser:x:1000:1000::/home/gouser:/bin/bash
gouser@e0dd620928c2:~$ grep gouser /etc/group
sudo:x:27:gouser
gouser:x:1000:
gouser@e0dd620928c2:~$ export | grep -E '(LAN|LC|TZ|GO)'
declare -x GO111MODULE="on"
declare -x GOLANG_VERSION="1.18.3"
declare -x GOPATH="/go"
declare -x LANG="C.UTF-8"
declare -x LANGUAGE="C"
declare -x LC_ALL="C.UTF-8"
declare -x TZ="Asia/Tokyo"
試しに別ターミナルでdocker-compose top、execをしてみる。upで立ち上がったbashと、execで立ち上げたbashの2プロセスが起動している。もう一度execすると3つ目のbashプロセスが同一コンテナで立ち上がる。
$ docker-compose -f docker-compose.dev.yml top
dev-env-golang
UID PID PPID C STIME TTY TIME CMD
-------------------------------------------------------------
1000 18191 18170 0 14:20 ? 00:00:00 /bin/bash
1000 18260 18170 0 14:20 ? 00:00:00 bash
$ docker-compose -f docker-compose.dev.yml exec golang bash
gouser@e0dd620928c2:~$
Makefile作成
環境操作を簡単に操作できるようにMakefileを作っておく。
.PHONY: \
env-create env-destroy env-down env-rmi env-build env-top env-images \
net-init net-deinit \
go-build go-up go-console go-stop go-down go-rmi
# 変数 --------------------------
# network addressを.envrcから取得
NETWORK_ADDR := $(shell grep 'NETWORK_ADDR' .env | sed -r 's/NETWORK_ADDR=(.+)/\1/g' )
# gateway addressを.envrcから取得
NETWORK_GATEWAY_IP := $(shell grep 'NETWORK_GATEWAY_IP' .env | sed -r 's/NETWORK_GATEWAY_IP=(.+)/\1/g' )
# 環境 --------------------------
env-create: net-init env-build
env-destroy: env-rmi net-deinit
env-down:
# 全コンテナ停止
-$(DC) down
env-rmi:
# 全コンテナ停止とイメージ削除
-$(DC) down --rmi all
env-build: go-build
env-top:
$(DC) top
# ネットワーク -------------------
net-init:
-$(D) network create --driver=bridge --subnet=$(NETWORK_ADDR) --gateway=$(NETWORK_GATEWAY_IP) dev-env-link
net-deinit:
-$(D) network remove dev-env-link
# golang環境 ---------------------
go-build:
$(DC) build --force golang
go-up:
$(DC) up -d golang
go-console: go-up
$(DC) exec golang bash
go-stop:
-$(DC) stop golang
go-down: go-stop
-$(DC) rm -f golang
go-rmi: go-down
-$(D) rmi -f dev-env-golang-image
ここまで。
作成した環境は GitHub を参照。
その他
この作業で便利なVSCode extension
- Docker(Microsoft)