$ Docker笔记

本文档基于18.09.2版本的docker。

$ Docker命令行

$ 镜像管理

$ docker pull

从镜像仓库中拉取或者更新指定镜像:

docker pull [OPTIONS] NAME[:TAG|@DIGEST]

如果速度较慢,可以配置镜像库:

编辑文件/etc/docker/daemon.json

{"registry-mirrors":["https://registry.docker-cn.com"]}

之后重新启动服务:

sudo systemctl daemon-reload
sudo systemctl restart docker

$ docker images

列出本地镜像:

docker images [OPTIONS] [REPOSITORY[:TAG]]

$ docker rmi

删除本地一个或多少镜像:

docker rmi [OPTIONS] IMAGE [IMAGE...]

$ docker tag

给本地镜像打上一个标签:

docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]

$ docker build

使用 Dockerfile 创建镜像:

docker build [OPTIONS] PATH | URL | -

$ docker history

查看指定镜像的创建历史:

docker history [OPTIONS] IMAGE

$ docker export

容器导出为tar归档文件:

docker export [OPTIONS] CONTAINER
OPTIONS:
    -o 写入文件,而不是标准输出

$ docker import

docker export导出的tar文件导入为镜像:

docker import [OPTIONS] file|URL|- [REPOSITORY[:TAG]]

$ docker save

将指定镜像保存成 tar 归档文件:

docker save [OPTIONS] IMAGE [IMAGE...]
Options:
    -o 写入文件,而不是标准输出

$ docker load

导入使用 docker save 命令导出的镜像:

docker load [OPTIONS]
Options:
    -i 从归档文件读入,而不是标准输入

$ 容器管理

$ docker run

创建一个新的容器并运行一个命令:

docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

$ docker exec

在运行的容器中执行命令:

docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
Options:
  -d, --detach               在后台运行命令
  -i, --interactive          以交互模式运行容器
  -t, --tty                  分配一个伪终端

$ docker ps

列出容器:

docker ps [OPTIONS]
    -a :显示所有的容器,包括未运行的。

$ docker top

查看容器中运行的进程信息,支持 ps 命令参数:

docker top [OPTIONS] CONTAINER [ps OPTIONS]

$ docker logs

获取容器的日志:

docker logs [OPTIONS] CONTAINER
Options:
  -f, --follow         跟踪日志输出
      --since string   显示从某时间戳之后的日志 (例如 2013-01-02T13:23:37) 或者相对时间 (例如 42m 从42分钟前开始)
      --tail string    Number of lines to show from the end of the logs (default "all")
  -t, --timestamps     显示时间戳
      --until string   显示到某时间戳之前的日志 (例如 2013-01-02T13:23:37) 或者相对时间 (例如  42m 到42分钟前截止)

$ docker start/stop/restart

docker start :启动一个或多个已经被停止的容器

docker stop :停止一个运行中的容器

docker restart :重启容器

docker start   [OPTIONS] CONTAINER [CONTAINER...]
docker stop    [OPTIONS] CONTAINER [CONTAINER...]
docker restart [OPTIONS] CONTAINER [CONTAINER...]

$ docker kill

杀掉一个运行中的容器:

docker kill [OPTIONS] CONTAINER [CONTAINER...]

$ docker rm

删除一个或多个容器:

docker rm [OPTIONS] CONTAINER [CONTAINER...]

$ 容器rootfs命令

$ docker commit

从容器创建一个新的镜像:

docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]

$ docker cp

在容器和本地文件系统之间拷贝文件和文件夹:

docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|-
docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH

$ docker diff

检查容器里文件结构的更改:

docker diff [OPTIONS] CONTAINER

$ 参考

$ Dockerfile配置

$ FROM

指定从哪个基础镜像开始构建:

FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]

$ ENV

设置环境变量:

ENV <key>=<value> <key>=<value> <key>=<value> ...
  • 可以指定多个
  • 对所有用户有效
  • 使用su切换用户后失效
  • 从构建过程到最终镜像都可见

参考:Dockerfile: create ENV variable that a USER can see? (opens new window)

$ COPY

向容器中拷贝文件和文件夹:

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

<dest>是绝对路径,或者相对WORKDIR的相对路径。

$ RUN

在build阶段执行,在新的layer上执行命令:

RUN <command>

$ CMD

为容器指定默认启动命令:

CMD ["executable","param1","param2"]

或者作为ENTRYPOINT的参数:

CMD ["param1","param2"]

注意:

Docker容器中的应用都应该以前台执行,对于容器而言,其启动程序就是容器应用进程,容器就是为了主进程而存在的,主进程退出,容器就失去了存在的意义,从而退出,其它辅助进程不是它需要关心的东西。

$ ENTRYPOINT

配置容器为可执行的:

ENTRYPOINT ["executable", "param1", "param2"]

$ VOLUME

创建挂载点:

VOLUME ["/data"]

$ 设置时区

RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
# 或者:
# RUN timedatectl set-timezone Asia/Shanghai

$ 中文乱码

RUN localedef -c -f UTF-8 -i zh_CN zh_CN.utf8
ENV LANG zh_CN.UTF-8

或者:

localectl set-locale LANG=zh_CN.UTF-8

$ 参考

$ Docker-Compose配置

//TODO

$ 最佳实践

$ 通用建议

使用多阶段 build

不安装不必要的包

解耦应用:将每个容器限制为一个进程。

最小化layer 数

将多行的参数排序

利用缓存:

  • 从缓存中已经存在的父映像开始,将下一条指令与从该基本映像派生的所有子映像进行比较,以查看其中是否有一个子映像是使用完全相同的指令构建的。
  • ADD和COPY指令比较的是 checksum 而非修改时间。
  • 除了ADD和COPY,其他指令比较的是指令字符串。

$ Dockerfile 指令

$ FROM

使用Alpine image基础镜像。

$ RUN

apt-get updateapt-get install 总是一块使用。

$ ADD or COPY

COPY优先于 ADD,COPY 指令更透明。

ADD 指令最佳用法:用于本地的tar 自动解压到 image 里。

$ USER

创建用户例子:

RUN groupadd -r postgres && useradd --no-log-init -r -g postgres postgres

$ WORKDIR

为了可读性和准确性使用绝对路径。

$ 参考

Best practices for writing Dockerfiles (opens new window)

$ 网络模式

docker 提供给了4种网络模式:bridge(默认),none,host和自定义网络。

当我们完成docker engine的安装以后会生成3种网络:bridge,none和host。

docker允许我们创建3种类型的自定义网络,bridge,overlay,MACVLAN 。

$ Host网络

docker build时使用host网络的方法:

docker build --network=host -t test .

docker-compose时使用host网络的方法:

version: '3.4'
services:
    zlggateway:
    build:
        context: gateway
        network: host
    ports:
      - "80:80"
      - "443:443"

docker run 时使用host网络的方法:

docker run --network=host  -i -t ubuntu:latest /bin/bash

注意:

docker run 使用的网络和docker build时使用网络,是两个独立的网络

docker-compose.yml中的network_mode、networks都不是build时的网络环境

参考:

docker - 关于network的一些理解 (opens new window)

Container networking (opens new window)

docker build以及docker run时使用host网络的方法 (opens new window)

$ 一些tricky技巧

1.如果配置的网络模式是默认的bridge模式,通常会选择暴露若干个服务的端口,但是容器创建以后有时想另外暴露几个端口,如何在不删除容器的情况下更改暴露的端口?

方式一:

可以在停止docker服务后修改/var/lib/container/<containerId>/hostconfig.json,以及/var/lib/container/<containerId>/config.v2.json这两个文件。

方式二:

HostIP=192.168.1.1
HostPort=30000
ContainerIP=172.17.0.2
ContainerPort=30000
iptables -t nat -A PREROUTING -p tcp -m tcp --dport ${HostPort} -j DNAT --to-destination ${ContainerIP}:${ContainerPort}
iptables -t nat -A POSTROUTING -d ${ContainerIP}/32 -p tcp -m tcp --sport 80 -j SNAT --to-source ${HostIP}
iptables -t filter -A INPUT -p tcp -m state --state NEW -m tcp --dport ${HostPort} -j ACCEPT

2.我们知道对容器中的hosts文件修改重启之后会失效,如何更改hosts使之不失效?

停止docker服务后修改/var/lib/container/<containerId>/hosts文件。

3.容器中的dubbo服务如何暴露容器而非宿主的ip?

指定配置参数:dubbo.protocol.host为容器的ip。

4.如何在容器中使用dmidecode?

docker run命令:

docker run --device /dev/mem:/dev/mem --cap-add sys_rawio --rm -it centos bash

或者docker-compose配置文件:

services:
  service1:
    devices:
      - "/dev/mem:/dev/mem"
    cap_add:
     - sys_rawio

5.MySQL镜像如何初始化数据库?

当Mysql容器首次启动时,会在/docker-entrypoint-initdb.d目录下扫描.sh,.sql,.sql.gz类型的文件。如果这些类型的文件存在,将执行它们来初始化一个数据库。这些文件会按照字母的顺序执行。

$ 参考

更新时间: 12/27/2022, 2:44:42 PM