使用Docker创建开发环境
最终的目标
使用Docker创建Go开发环境,以构建基于Go语言的Web应用程序。
目标
-
- Docker上にコンソール立ち上げ環境を作る。 ← 今ここ
フレームワークginを使った簡単なREST APIサーバーを立ち上げる。
イメージビルド時にプログラムをコンパイルしコンテナ起動と同時にホストPCからAPIにアクセスできるようにする。
前往的选择
现在(2022/06/04)最新版本的go是1.18.3。
1. 在1.17和1.18中进行了重大的规范变更(引入泛型,Fuzzing成为标准功能)。相较之前的升级来说,这是最大的变化了吧?
泛型将在1.19版本正式推出,在1.18版本中还处于试验性实现阶段。
本来考虑选择稳定的1.17版本,但为了学习的目的,决定选择最新的1.18版本,并开始使用泛型。
因此,我们将采用1.18系列。
选择Docker镜像
如果考虑在云上部署,那么会涉及到使用Linux环境。在选择Linux发行版时,如果想在开发期间有更多的自由度,那就选择Ubuntu。
我本来想要选择以Ubuntu的LTS为基础,但是没有基于Ubuntu的golang镜像…
因为Debian有镜像可用,所以我选择了Debian。
Debian当前的LTS是Stretch,但将于6月30日到期…
下一步是使用Debian 10“Buster”,有效期至2024年6月。让我们升级到buster吧。
将Golang的版本固定,并在必要的时候升级到较小的版本(第三个数字)。
图像版本为1.18.3-buster。
如果图片大小很大,我们可以考虑使用alpine来部署环境。
创建Dokerfile
希望将部署到云端时所需的Dockerfile和开发环境所需的Dockerfile分开。
为了能够通过make命令启动,将Dockerfile放在env目录下集中管理。
./
+ 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
Dockerfile的改写
使用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中进行构建、启动和执行。之所以不使用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。如果再次执行exec命令,将会在同一个容器中启动第三个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扩展工具
- Docker(Microsoft)