Maurice Wu
Published on

Docker 备忘

# 启动 docker 服务
sudo service docker start
# 交互方式启动
docker run -it ubuntu bash
# 后台服务模式启动
docker run -d ubuntu bash -c "while true; do echo hello world;
sleep 1; done"
# 映射端口和数据卷
docker run --name mongo --port 2234:80 -v /tmp/data:/data/db
# 进入处于后台模式的容器
docker exec -it [container id] /bin/bash
# 查看某个命令的用法
docker --help
docker [command] --help
# 查看输出
docker logs containerid

# 删除容器
docker rm -f containerid
# 查看容器的端口信息
docker port containerid

# 查看容器网络信息
docker network inspect bridge

国内镜像源

使用 docker 国内的官方源 https://registry.docker-cn.com

或者是网易的镜像源http://hub-mirror.c.163.com

网易的源会快一点。

cd ~/.docker
vim daemon.json
{
  "experimental" : false,
  "debug" : true,
  "registry-mirrors": ["https://registry.docker-cn.com"]

}

Docker run

设置环境变量

docker run -e NODE_ENV=prod node index.js
docker run --env-file .env node index.js

重启

docker run --restart=on-failure node index.js

docker commit

如果一个容器内的文件有改动需要生成新的镜像就可以使用 docker commit 。

# 为 ubuntu 镜像添加 curl 工具
docker run -it ubuntu bash
# 在容器内
apt-get update
apt install net-tools
aput install curl

# 在宿主机的终端提交
docker commit [container id] ubuntu_nettools_curl

docker 限制容器的 cpu 和内存

tag 概念

多阶段构建

什么情况下会生成中间镜像

容器网络连接

none 模式

容器没有网卡,ip,路由等信息,需要自行配置。这种方式网络隔离最彻底。

host 模式

docker 容器使用宿主机的 ip 和端口,但是文件系统还是隔离的,最大好处就是性能。

docker run --network host nginx
docker run --network host ubuntu
# 在 ubuntu 容器里面可以这样访问 nginx
curl http://localhost:80

注意:mac 版本的 docker host 模式有点不一样,以上在 ubuntu docker 测试通过。

bridge 模式

docker 启动后创建一个虚拟网桥 docker0,宿主机和容器都连接到这个网桥上面,并且都分配了处于该子网段的 ip,通过这种方式,不同容器之间,容器和宿主机器之间可以通过子网段 ip 地址互联。docker 默认为桥接模式,可以将容器和宿主机都想象成连接到同一网关的不同机器。

docker 默认的网络模式就是 bridge 模式。虽然它比 host 模式更复杂,但是也更安全。

docker bridge mode

如下图,在 ubuntu 中,宿主机有两个不同的网卡,eth0 是主机内网 ip 地址,而主机在 docker0 网桥上的地址是 172.17.0.1。

docker host and bridge

容器内的 IP:

container IP

由此可知他们在同一网段下。

在开发调试的时候,bridge 模式的容器要访问宿主机的 ip,还可以通过 host.docker.internal 这个指定的 DNS 名称来访问。

通过自定义 bridge 模式实现容器互联

虽然在 bridge 模式下容器之间可以通过子网段的 ip 地址互联,但是无法保证 docker 每次启动后都是 docker0 的网段都是一样的。所以需要一种别名的方式来代替各容器的 ip 地址。

针对外界网络,自定义 bridge 模式提供了更好的隔离型,而针对同一 bridge 下的容器,则有更好的互通性。

具体步骤如下:

  1. 创建自定义 bridge
docker network create -d bridge my-net
  1. 将容器连接到该 bridge
docker network connect my-net nginx_demo
docker network connect my-net ubuntu_demo
  1. 进入容器检查互通性
docker exec -it ubuntu_demo bash
# 可以通过容器名称访问容器
curl http://nginx_demo
  1. 断开和默认网桥的连接
docker network disconnect bridge nginx_demo
docker network disconnect bridge ubuntu_demo

Dockerfile

docker build

docker build [options] PATH | URL

docker build 需要 Dockerfile  和 context 。 context  可以是本地文件路径或者是一个 git 仓库的地址。构建的时候会将整个 context 的内容上传到 docker daemon。删除不必要的文件可以加快构建过程。

# 默认 Dockfile 的位置为 context 的第一级目录
# 指定 Dockerfile 的位置和 context 为当前路径
docker build -f /path/Dockfile .

docker 会在构建的时候使用中间镜像来加速构建。

格式

  1. 行首为 # 的都视为注释
  2. 可以在 FROM 指令前面的,只有 parser directives, comments, 和 global args.
  3. 使用 \ 作为行连接符
  4. 指令建议都用大写

parser directives

编译指定以键值对注释的形式放在 Dockerfile 文件的最顶层。不是放在最顶层的 parser directives 都视为普通注释。目前支持的 parser directives 有:

  • syntax: 指定 Dockerfiel builder 的位置。
# syntax=docker/dockerfile
# syntax=docker/dockerfile:1.0
# syntax=docker.io/docker/dockerfile:1
# syntax=docker/dockerfile:1.0.0-experimental
# syntax=example.com/user/repo:tag@sha256:abcdef...

这个只有在启用 Buildkit 的时候才会起作用,如果不想使用 Docker build 新的特性的话,保持默认不指定就好。

escape

# escape=\

指定 Dockerfile 的行连接符, 默认是反斜杠。

ENV 指令

ENV key value
ENV key=value

ENV mycat Jonhn jeffy
# 等价于
ENV mycat=John\ jeffy

在 Dockerfile 文件中可以用 variablename或者{variablename} 或者 variablename 的形式引用。

FROM busybox
ENV foo /bar
WORKDIR ${foo}   # WORKDIR /bar
ADD . $foo       # ADD . /bar
COPY \$foo /quux # COPY $foo /quux

ENV 指定设置的环境变量会一直存在于镜像中 。这个可能会造成一些影响。在单个指令中指定环境变量,可以这样做:

RUN key=value command

.dockerignore

dockerignore 文件允许你指定包含或者忽略哪些文件参与构建。忽略的文件将不会发送到 docker daemon。

# 忽略所有 md 文件
*.md
# 但是允许 readme md
!readme*.md
# /somedir/temporary.txt
*/temp*
# /somedir/subdir/temporary.txt
*/*/temp*
# ** 表示任意层级的文件夹
# /temp
# /dir/temp
**temp

ARG

在 Dockfile 的顶部设置变量以供后面的命令使用

ARG VERSION=latest
FROM node:${VERSION}

FROM

FROM 指令指定镜像的基础镜像。

FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]
  • 多阶段构建的时候一个 Dockerfile 文件里面有多个 FROM 指令。
  • Tag 是可选的,如果不指定,默认是 latest
  • name 用于多阶段构建时 COPY 指令 COPY --from=<name|index>

RUN

两种形式

RUN command paramer1
# 必须使用双引号
RUN ["command", "paramer1"]

RUN 命令默认会生成 cache,也就是中间镜像,以供下次构建,可以通过命令指定不生成 cache。

docker build --no-cache .

CMD

CMD 有三种形式

  • CMD ["executable","param1","param2"]  (exec form, this is the preferred form)
  • CMD ["param1","param2"] (as default parameters to ENTRYPOINT)
  • CMD command param1 param2 (shell form)
CMD ["sh", "-c", "/usr/start.sh", "--someflag"]
# 等价于
CMD sh -c /usr/start.sh --someflag

如果数组中的第一个元素不是可执行,则是第二种形式,作为 ENTRYPOINT 的参数,

会被 docker run 和 ENTRYPOINT 覆盖。

ENTRYPOINT

ENTRYPOINT 有两种形式

# exec form
ENTRYPOINT ["executable", "param1", "param2"]
# shell form
ENTRYPOINT command param1 param2

CMD 和 ENTRYPOINT 都可作为启动容器时默认的执行命令,他们的相互作用如下表

No ENTRYPOINTENTRYPOINT exec_entry p1_entryENTRYPOINT [“exec_entry”, “p1_entry”]
No CMDerror, not allowed/bin/sh -c exec_entry p1_entryexec_entry p1_entry
CMD [“exec_cmd”, “p1_cmd”]exec_cmd p1_cmd/bin/sh -c exec_entry p1_entryexec_entry p1_entry exec_cmd p1_cmd
CMD [“p1_cmd”, “p2_cmd”]p1_cmd p2_cmd/bin/sh -c exec_entry p1_entryexec_entry p1_entry p1_cmd p2_cmd
CMD exec_cmd p1_cmd/bin/sh -c exec_cmd p1_cmd/bin/sh -c exec_entry p1_entryexec_entry p1_entry /bin/sh -c exec_cmd p1_cmd

容器的启动命令,Dockerfile 中可以有多条 ENTRYPOINT,但只有最后一条生效。

CMD 和 docker run 之后的参数会当作参数传给 ENTRYPOINT。

LABEL

指定镜像的标签

LABEL author=jelee

# 使用 docker inspect 查看镜像标签
docker image inspect --format="" myimage

{
	"author": "jelee"
}

EXPOSE

EXPOSE <port1> [<port2>/<protocol>...]
EXPOSE 80 80/tcp

声明容器要监听的宿主机端口 port1 要转发的 容器内端口 port2,同时指定端口协议为 tcp。

可以通过 docker run -p 8888:80/tcp 命令覆盖。

ADD COPY

ADD [--chown=<user>:<group>] <src>... <dest>
ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]
COPY [--chown=<user>:<group>] <src>... <dest>
COPY [--chown=<user>:<group>] ["<src>",... "<dest>"]

# 添加所有 hom 开头的文件
ADD hom* /mydir/
# ? 表示单个字符
ADD hom?.txt /mydir/

这两个命令都是用来将 src (可是是 url 或者是文件,文件夹)复制到镜像 dest中。区别:

  1. COPY 只复制 src 文件夹中的内容,不包括自身文件夹
  2. COPY 可指定 --from=<name|index> 从中间镜像中复制内容
  3. 在 ADD 中,如果src 是 tar,zip,tgx, xz 等归档文件,将会自动解压

相关错误

  1. docker 映射端口报错
    driver failed programming external connectivity on endpoint nervous_villani

解决办法: 重启docker

systemctl restart docker
  1. 打包镜像的时候安装 yarn,执行失败

解决办法是 :

RUN curl -o- -L https://yarnpkg.com/install.sh | bash
RUN $HOME/.yarn/bin/yarn install

参考

docker 网络模式

容器访问宿主机ip

Docker 容器间通信方法