開發日常都會接觸到容器和docker
,以下作記錄:
實現原理
- 資源控制(
CPU/Memory/IO
等):cgroups - 資源隔離: Linux namespaces, chroot 等
- 存儲原理: aufs, OverlayFS 等
- 容器邊界安全:AppArmor, SELinux, seccomp
- 容器底層實現OCI:lxc, libcontainer, runc, containerd 等
- 容器運行時接口CRI:docker, cri-o,kata-containers, frakti 等
- 用
c
實現簡單的容器環境
Dockerfile
- 採用和遵循multi-stage builds 做法, 編譯和運行使用不同的基礎鏡像。
- 承接上一點,由於常規配置下(
docker run
不加任何參數),docker
與宿主機高度隔離,此時docker運行環境的時區timezone
等設置往往是空白的, 如FROM alpine:latest
, 此時, 若應用邏輯依賴時間或時區, 如某golang
程序:
loc, _ = time.LoadLocation("Asia/Shanghai")
t := time.Unix(t1, 0).In(loc)
則docker
運行環境需要添加依賴:
FROM alpine:latest
RUN apk --no-cache tzdata
-
對於
golang
開發的app
,每次構建時均要下載依賴的dockerfile
, 可使用goproxy
加快依賴下載速度, 而其配置因go版本而異, 如go 1.12ENV GOPROXY=https://goproxy.cn
-
Docker
的入口程序與Kubernetes
的入口程序Dockerfile
用於製作鏡像,可以在文件最後指定ENTRYPOINT
作爲鏡像的入口程序,即pid
爲1
的進程。- 在
Kubernetes
用於啓動pod
的yaml
中,也可指定Command
和Args
作爲Docker
啓動後的入口程序, 即pid
爲1
的進程。 - 若
1
號進程退出(儘管入口程序派生了其他後臺進程),則Docker
退出。 - 若
docker
是通過docker run
啓動的,docker
會完成生命週期,docker
進程會退出。 - 若
docker
是通過Kubernetes deployment
啓動的,則pod
中的docker
在執行完入口程序後會退出,導致pod
不斷重啓,入口程序反覆執行。 - 一般做法會在入口程序的最後添加類似
shell
的sleep infinity
等語句阻止1
號進程退出,使得1號進程派生的後臺進程能持續服務。 Docker
和Kubernetes
入口程序先後關係:若在dockerfile和k8s中均指定入口程序,則有如下先後關係, 即使用Kubernetes
創建的docker
若指定了Command
,則該docker
鏡像的ENTRYPOINT
會被覆蓋, 相當於調用了docker run ... --entrypoint
:
If you do not supply command or args for a Container,
the defaults defined in the Docker image are used.
If you supply a command but no args for a Container, only the supplied command is used.
The default EntryPoint and the default Cmd defined in the Docker image are ignored.
If you supply only args for a Container,
the default Entrypoint defined in the Docker image is run with the args that you supplied.
If you supply a command and args,
the default Entrypoint and the default Cmd defined in the Docker image are ignored. Your command is run with your args.