Docker笔记

Linux无法以用户身份运行docker

在shell里以用户登录,docker pull报错

1
Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock
1
2
3
sudo groupadd docker # 添加docker用户组
sudo gpasswd -a $USER docker # 添加当前用户到docker用户组
newgrp docker # 更新docker用户组

然后可以以普通用户身份运行docker命令

Alpine容器内设置时区

标签alpine:latest的容器内,时区默认是UTC,不受宿主机的时区设置影响。所以打印出来的日志中的时间戳是错误的。

Golang标准库time.LoadLocation之类的函数依赖操作系统的实现,而alpine镜像没有安装对应的库

1
time.LoadLocation("Asia/Shanghai")

会提示无法找到”Asia/Shanghai”时区

解决方法

1
2
3
4
# Dockerfile
FROM alpine:latest

RUN apk add --no-cache tzdata

在docker-compose或者启动容器时指定TZ环境变量

1
2
3
4
5
6
version: '3'
services:
jerry:
image: yangrq1018/jerry
environment:
TZ: "Asia/Shanghai"

时间戳显示正确

1
2
3
4
5
6
7
8
❯ docker logs jerry
2021/11/14 11:13:38 bot version: jerry/1.0.2 (dirty), built on 2021-11-14, last commit f33e14e@master
[INFO] | LOG | 2021/11/14/ 11:13:39 | Logger initialised.
2021/11/14 11:13:41 check bot network
2021/11/14 11:13:41 Network env "http_proxy":
2021/11/14 11:13:41 Network env "https_proxy":
2021/11/14 11:13:41 Network env "HTTP_PROXY": http://host.docker.internal:7890
2021/11/14 11:13:41 Network env "HTTPS_PROXY": http://host.docker.internal:7890

容器访问主机的端口 && 使用主机网络代理

在墙内环境下,docker build里的包下载很慢而且容易卡住失败,这时我们想要在容器内部设置代理。 容器的网络流量可以使用主机提供代理服务,或者通过docker container networking,使用运行在另一个容器内的代理服务,如clash。

方法1:最简单粗暴,在Dockerfile里hardcode

1
2
#...
ENV HTTP_PROXY http://host:7890

缺点也是显而易见的,其他人拉取的镜像中也会有这个环境变量,而且无法消除或者更改。如果更换了代理地址,镜像也需要重新编译。这个方法只适合需要走公司的proxy server上网的环境,镜像只是内部使用。

方法2:配置~/.docker/config.json

1
2
3
4
5
6
7
8
9
{
"proxies":
{
"default":
{
"httpProxy": "http://host-ip:7890",
"httpsProxy": "http://host-ip:7890",
}
}

这里的值会直接被设置为容器内部的HTTP_PROXY环境变量的值,所以需要填写主机的局域网IP地址而不是127..0.0.1或者localhost。这种方法对所有在本机上docker build的容器都有效,不影响其他人拉取的镜像,适合在开发环境上使用。

警告:如果你在使用docker-compose的Container Networking,需要service容器之间通过容器组网通信,不要使用方法1或2!会和容器的组网冲突,导致无法使用其他容器的container name进行dns寻址。这种情况下建议只在编译过程中走代理,容器运行时不要走任何代理,参考方法3

方法3:使用build_args编译时变量 docker-compose.yml

1
2
3
4
5
6
build:
context: .
dockerfile: ./trade/scraper/Dockerfile
args:
http_proxy: "http://172.17.0.1:7890"
https_proxy: "http://172.17.0.1:7890"

用Docker Desktop的情况可以不用默认的静态IP,用host.docker.internal,但Linux Docker不支持,还 是填写docker default network里宿主机的默认IP 172.17.0.1。但经检测,在容器运行环境里,所以平台都可以正常使用host.docker.internal域名来引用宿主机。

docker build命令,同理docker build --build-arg http_proxy="..."

Windows Docker Desktop

WSL2版本的Windows Docker Desktop,容器配置存储在\\wsl.localhost\docker-desktop-data\data\docker\containers(直接在 文件资源管理器的地址栏里粘贴即可)。例如想要修改已经启动的容器的Network port mapping, 编辑\\wsl.localhost\docker-desktop-data\data\docker\containers\{id}\hostconfig.json 中的PortBindings字段,注意要关闭docker service,否则修改会被覆盖,修改保存后重启docker,启动容器,就可以在Docker Desktop里看到Port Binding更新啦。