本文不是docker的入门教程,不会涉及过多的概念解释,只是作为学习笔记,更多的是一些docker的常用命令,方便温习和快速查询。
常用镜像命令
Docker镜像(Image)就是一个只读的模板。镜像可以用来创建Docker容器,一个镜像可以创建多个容器。
- 获取镜像
# docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签]
docker pull ubuntu:18.04
- 列出已经下载的镜像
docker images
# 列出某个镜像
docker images centos
- 删除某个镜像
# 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)
- 提交镜像
注意,不要使用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
指令会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。- 因此在
COPY
和ADD
指令中选择的时候,可以遵循这样的原则,所有的文件复制均使用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
所设置的命令时一定会被执行ENTRYPOINT
和CMD
可以联合使用,ENTRYPOINT
设置执行的命令,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的不同点
- 两者声明变量的作用域不同
ARG
只存在于构建环境,在将来容器运行时是不会存在这些环境变量的,而ENV可带到容器中。ARG
指令有生效范围,如果在FROM
指令之前指定,那么只能用于FROM
指令中。对于多阶段构建要注意这个问题
- 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 容器:容器内路径 目的主机路径
容器卷
运行容器时挂载
- 匿名挂载
# -v 容器内路径
docker run -d -P -v /etc/nginx --name nginx01 nginx
- 具名挂载
# -v 卷名:容器内路径,卷名全面没有/,有/则表示是指定路径挂载
docker run -d -P -v has-name-nginx:/etc/nginx --name nginx01 nginx
- 指定路径挂载
# -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