Docker 常用命令

521 阅读9分钟

本文不是docker的入门教程,不会涉及过多的概念解释,只是作为学习笔记,更多的是一些docker的常用命令,方便温习和快速查询。

常用镜像命令

Docker镜像(Image)就是一个只读的模板。镜像可以用来创建Docker容器,一个镜像可以创建多个容器。

  1. 获取镜像
# docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签]
docker pull ubuntu:18.04
  1. 列出已经下载的镜像
docker images
# 列出某个镜像
docker images centos
  1. 删除某个镜像
# docker image rm [选项] <镜像1> <镜像2>
# 等同于 docker rmi [选项] <镜像1> <镜像2>
# 镜像可以是镜像ID(长ID或者短ID都可以),也可以是镜像名称
docker rmi 501
docker rmi centos

# 用docker images ls命令来配合
# 比如:删除所有仓库名为redis的镜像,-q表示列出镜像的ID
docker rmi $(docker images -q redis)
  1. 提交镜像

注意,不要使用docker commit 定制镜像,定制镜像应该使用Dockerfile来完成,docker commit只适用于一些特殊的场景

# docker commit [options] <容器ID或容器名> [<仓库名>[:<标签>]]
# 将容器(webserver)保存为镜像(nginx:1.2)
docker commit --message "修改了NGINX" webserver nginx:1.2

Dockerfile

FROM  指定基础镜像

# 指定nginx作为基础镜像
FROM nginx

# 指定空白镜像
FROM scratch

RUN  执行命令

  • shell 格式:RUN <命令>,就像直接在命令行中输入的命令一样
  • exec 格式:RUN ["可执行文件", "参数1", "参数2"],更像是函数调用中的格式
FROM nginx
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html

注意:Dockerfile中每个指令都会建立一层,因此,指令最好使用&&合并执行,而不是每个指令都执行一个RUN

FROM debian:stretch

RUN set -x; buildDeps='gcc libc6-dev make wget' \
&& apt-get update \
&& apt-get install -y $buildDeps \

COPY 复制文件

# COPY [--chown=<user>:<group>] <源路径>... <目标路径>
  • 源路径可以是多个,也可以是通配符
COPY hom?.txt /mydir/
  • 目标路径可以是容器内的绝对路径,也可以是相对于工作目录的相对路径。目标路径可以不需要事先创建
  • 如果源路径为文件夹,复制的时候不是直接复制该文件夹,而是将文件夹中的内容复制到目标路径。
COPY package.json /usr/src/app/
COPY --chown=55:mygroup files* /mydir/

ADD 更高级的复制功能

和COPY指令类似,比COPY指令新增了自动解压缩的功能

FROM scratch
ADD ubuntu-xenial-core-cloudimg-amd64-root.tar.gz /
ADD --chown=bin files* /mydir/
  • ADD 指令会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。
  • 因此在 COPYADD 指令中选择的时候,可以遵循这样的原则,所有的文件复制均使用 COPY 指令,仅在需要自动解压缩的场合使用 ADD

CMD 容器启动命令

Docker 不是虚拟机,容器就是进程。既然是进程,那么在启动容器的时候,需要指定所运行的程序及参数。CMD 指令就是用于指定默认的容器主进程的启动命令的。

RUN相似,也是两种格式

  • bash 格式:CMD <命令>
  • exec 格式:CMD ["可执行文件","参数1",”参数2“]
    • 一般推荐使用 exec 格式
    • 这类格式在解析时会被解析为 JSON 数组,因此一定要使用双引号 ",而不要使用单引号。
# shell 格式
CMD echo $HOME
# 在实际执行中,会变更为exec格式
CMD [ "sh", "-c", "echo $HOME" ]

在运行时可以指定新的命令来替代镜像设置中的这个默认命令,比如,ubuntu 镜像默认的 CMD/bin/bash,如果我们直接 docker run -it ubuntu 的话,会直接进入 bash。我们也可以在运行时指定运行别的命令,如 docker run -it ubuntu cat /etc/os-release。这就是用 cat /etc/os-release 命令替换了默认的 /bin/bash 命令了,输出了系统版本信息。

# ubuntu镜像默认的CMD是/bin/bash,这里改成cat /etc/os-release
docker run -it ubuntu cat /etc/os-release

容器没有前后台的概念,因此不能使用以下命令

# 这是错误的!
CMD service nginx start

ENTRYPOINT 入口点

CMD的区别

  • CMD设置的命令,可以在docker run时传入其他命令,覆盖掉CMD的命令,但是ENTRYPOINT所设置的命令时一定会被执行
  • ENTRYPOINTCMD可以联合使用,ENTRYPOINT设置执行的命令,CMD传递参数

参考:RNTRYPOINT和CMD的区别

ENV 设置环境变量

# 两种格式
# ENV <key> <value>
# ENV <key1>=<value1> <key2>=<value2>...

ENV VERSION=1.0 DEBUG=on \
    NAME="Happy Feet"

ARG 构建参数

# ARG <参数名>[=<默认值>]
ARG VERSION=2.0.1

ARG与ENV的区别

参考:ARG和ENV的不同点

  1. 两者声明变量的作用域不同
  • ARG只存在于构建环境,在将来容器运行时是不会存在这些环境变量的,而ENV可带到容器中。
  • ARG指令有生效范围,如果在 FROM 指令之前指定,那么只能用于 FROM 指令中。对于多阶段构建要注意这个问题
  1. ARG在构建镜像时可以通过-build-arg参数改变变量值
docker build -f Dockerfile.ARG -t ipinfo-arg-2.0.0 --build-arg VERSION=2.0.0 .

WOKRKDIR 指定工作目录

使用 WORKDIR 指令可以来指定工作目录(或者称为当前目录),以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR 会帮你建立目录。 不能把Dockerfile等同Shell脚本来写

RUN cd /app
RUN echo "hello" > world.txt

以上命令并不能找到/app/world.txt文件,这是因为,在 Dockerfile 中,这两行 RUN 命令的执行环境根本不同,是两个完全不同的容器。

每一个 RUN 都是启动一个容器、执行命令、然后提交存储层文件变更。第一层 RUN cd /app 的执行仅仅是当前进程的工作目录变更,一个内存上的变化而已,其结果不会造成任何文件变更。而到第二层的时候,启动的是一个全新的容器,跟第一层的容器更完全没关系,自然不可能继承前一层构建过程中的内存变化。

因此如果需要改变以后各层的工作目录的位置,那么应该使用 WORKDIR 指令。

WORKDIR /app
RUN echo "hello" > world.txt

如果你的 WORKDIR 指令使用的相对路径,那么所切换的路径与之前的 WORKDIR 有关:

WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd

RUN pwd 的工作目录为 /a/b/c。 参考:WOKRKDIR 指定工作目录

USER 指定当前用户

USER 指令和 WORKDIR 相似,都是改变环境状态并影响以后的层。WORKDIR 是改变工作目录,USER 则是改变之后层的执行 RUN, CMD 以及 ENTRYPOINT 这类命令的身份。 注意,USER 只是帮助你切换到指定用户而已,这个用户必须是事先建立好的,否则无法切换。

RUN groupadd -r redis && useradd -r -g redis redis
USER redis
RUN [ "redis-server" ]

EXPOSE 暴露端口

# EXPOSE <端口1> [<端口2>...]

EXPOSE指令告诉Docker正在运行的容器侦听特定的网络端口。这只是一个声明,在容器运行时并不会因为这个声明应用就会开启这个端口的服务。这可以作为一种端口映射文档,然后可以在发布端口时使用。这样做有两个好处:

  • 一个是帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射
  • 另一个用处则是在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口

VOLUME 定义匿名卷

# VOLUME ["<路径1>", "<路径2>"...]
# VOLUME <路径>
VOLUME /data

运行容器时可以覆盖这个挂载设置

# docker container run -d -v <Volume name:Dockerfile VOLUME path>
docker run -d -v mydata:/data xxxx

在这行命令中,就使用了 mydata 这 个位置,替代了 Dockerfile 中定义的匿名卷的挂载配置。

构建镜像

# 在Dockerfile文件所在目录执行:docker build [OPTIONS] PATH | URL 
docker build -t nginx:v3 .

参考:镜像构建上下文

常用容器命令

新建并启动容器

# docker run [options] image [command] [arg...]
# --name 容器m
# -d 后台运行容器,并返回容器ID,也即启动守护式容器
# -i 以交互模式运行容器,通常与-t同时使用
# -t 为容器重新分配一个伪输入终端,通常与-i同时使用

docker run ubuntu:18.04 /bin/echo 'Hello world'
Hello world

docker run -t -i ubuntu:18.04 /bin/bash
root@af8bae53bdd3:/#

列出当前所有正在运行的容器

# docker ps [options]
# 示例
docker ps -l
docker ps -a
docker ps -n 5

退出当前容器

  • exit: 容器停止退出
  • ctrl + P + Q:容器不停止退出
  • 启动容器
docker start 容器
  • 停止容器
# 温柔停止
docker stop 容器
# 强制停止
docker kill 容器
  • 删除已经停止的容器
docker rm 容器

使用docker ps -a进行查看,发现容器已经退出。这是因为,Docker容器后台运行,就必须有一个前台进程 容器运行的命令如果不是那些一直挂起的命令(比如运行top,tail),就会自动退出。

查看容器日志

# -t 加入时间戳
# -f 跟随最新的日志打印
# --tail 数字,显示最后多少条
docker logs -f -t --tail 容器id

查看容器内运行的进程

docker top 容器

查看容器内部细节

docker inspect 容器名称或者容器ID

进入正在运行的容器并以命令行交互

# 在容器外面执行
docker exec -it 容器
# 示例
docker exec -t 容器 ls -l /tmp

# 进入容器中
docker attach 容器

从容器内拷贝文件到主机

docker cp 容器:容器内路径 目的主机路径

容器卷

运行容器时挂载

  1. 匿名挂载
# -v 容器内路径 
docker run -d -P -v /etc/nginx --name nginx01 nginx
  1. 具名挂载
# -v 卷名:容器内路径,卷名全面没有/,有/则表示是指定路径挂载
docker run -d -P -v has-name-nginx:/etc/nginx --name nginx01 nginx
  1. 指定路径挂载
# -v /宿主机路径:容器内路径
docker run -d -P -v /usr/local/nginx/has-name-nginx:/etc/nginx --name nginx01 nginx

通过Dockerfile的VOLUME指令进行匿名挂载

# VOLUME ["卷名1", "卷名2"...]
# VOLUME <路径>

VOLUME /data

运行容器时的挂载会覆盖Dockerfile中定义的匿名挂载

读写权限

# ro 只读 该路径只能通过宿主机来操作,容器内容是无法操作的。
# rw 可读可写
docker run -d -P -v has-name-nginx:/etc/nginx:ro --name nginx01 nginx

数据卷容器

实现多个容器之间的容器卷共享

# 使用--volumes-from,继承nginx02继承nginx02d
docker run -d -P  --name nginx02 --volumes-from nginx01 nginx

查看所有容器卷

ubuntu@VM-0-12-ubuntu:~$ docker volume ls
DRIVER              VOLUME NAME
local               8663a23e21398611059d6101da999f711d7de2145cef6166d2883b2dff625a11   # 匿名卷
local               jenkins_home  # 具名卷

所有的docker容器内的券,没有指定目录的情况下都是在/var/lib/docker/volumes目录下。

docker compose

# 用于部署一个 Compose 应用。默认情况下该命令会读取名为 docker-compose.yml 或 docker-compose.yaml 的文件。
# 通常情况下,会使用 -d 参数令应用在后台启动。
docker compose up -d

# -f  指定使用的 Compose 模板文件,默认为 docker-compose.yml,可以多次指定,指定多个yml。
docker-compose -f docker-compose.yml up -d

# 验证(docker-compose.yml)文件配置,当配置正确时,不输出任何内容,当文件配置错误,输出错误信息。 
docker compose config  -q

# 查看启动的服务
docker compose ps
# 列出指定服务的容器
docker compose ps eurek

# 停止 Compose 应用相关的所有容器,但不会删除它们。
docker compose stop

# 用于删除已停止的 Compose 应用。它会删除容器和网络,但是不会删除卷和镜像。推荐先执行 docker compose stop 命令来停止容器。
docker compose rm

# 启动已经存在的服务容器。
docker compose start

# 重启已停止的 Compose 应用。
docker compose restart

# 停止并删除运行中的 Compose 应用
docker compose down

# 查看日志
docker-compose logs -ft --tail 10 nginx

# 进入容器内部
 docker compose exec nginx bash