Docker 常用命令与 Dockerfile
Docker 常用命令与 Dockerfile
日常会反复查的 Docker 命令,以及 Dockerfile 各指令的语义。镜像、容器、数据卷、构建,按这几块整理。
镜像
镜像本身只读,容器从镜像启动时 Docker 会在镜像最上层加一个可写层,镜像不变。
sudo docker pull busybox:latest # 拉镜像
sudo docker images # 列出本地镜像
sudo docker rmi <image_id> # 删镜像(有容器在用要先删容器)
sudo docker search mysql # 搜索镜像
sudo docker tag SOURCE_IMAGE:TAG TARGET_IMAGE:TAG # 打标签
基于已有容器提交成新镜像:
sudo docker run -it <image_id> # 运行并进入容器
exit # 退出
sudo docker commit -m "Added a new test file" -a "author" <container_id> test
镜像打包成 tar / 从 tar 加载:
sudo docker save -o test_local.tar test # 导出
sudo docker load -i test_local.tar # 导入
save/load 走镜像,保留完整历史和元数据,体积大;export/import 走容器,丢历史和元数据,体积小。一般用前者。
容器
容器是镜像的运行实例,相互隔离。可以把它当一个简易 Linux 环境。
sudo docker ps -a # 列出所有容器
sudo docker create busybox # 创建容器
sudo docker run -d busybox /bin/sh -c "while true; do echo hello world; sleep 1; done" # 后台运行
sudo docker logs <container_id> # 看日志
sudo docker logs -f <container_id> # 持续看日志
sudo docker stop <container_id> # 停止
sudo docker stop <container_id> -t 1 # 1 秒内杀掉
sudo docker restart <container_id> # 重启
sudo docker pause/unpause <container_id># 暂停/恢复
sudo docker rm <container_id> # 删除
sudo docker rm -f <container_id> # 强删运行中的容器
进入容器有两种,exec 比 attach 好用:
sudo docker attach <container_id> # 进入,exit 后容器会停
sudo docker exec -it <container_id> /bin/bash # 进入,exit 后容器仍在跑(常用)
# CentOS 基础镜像把 /bin/bash 换成 /bin/sh
端口映射,多个端口加多个 -p:
sudo docker run -p 8080:8080 -p 3000:30000 <container_id>
私有仓库
sudo docker run -d -p 5000:5000 registry # 本地 5000 访问容器 5000
仓库(Repository)是一组关联镜像的集合,注册服务器(Registry)是存实际镜像文件的地方。
从非官方仓库拉镜像若提示 Invalid registry endpoint,是 Docker 1.3.0 之后加强了镜像安全校验,需要在 Docker 配置里加 Docker_OPTS="--insecure-registry dl.dockerpool.com:5000" 后重启服务。
数据卷
容器管理数据有两种方式:数据卷(Data Volumes)和数据卷容器(Data Volume Containers)。
数据卷是给容器用的特殊目录,绕过文件系统,可在容器间共享和重用,修改立即生效,卷会一直存在直到没有容器使用。
# 在容器内创建数据卷 /data_1, -v 绑定挂载
sudo docker run -d -ti -P --name volume_demo_1 -v /data_1 busybox
sudo docker inspect <container_id> # 看挂载点 "Mounts"
# 把本地目录挂进容器,--rm 容器结束自动销毁
sudo docker run --rm -it -v ~/data_2:/data_2 busybox
数据卷容器适合多容器共享持续更新的数据:
# 创建数据卷容器
sudo docker run -it -v /dbdata --name dbdata busybox
# 其他容器用 --volumes-from 挂载
sudo docker run -it --volumes-from dbdata --name db1 busybox
sudo docker run -it --volumes-from dbdata --name db2 busybox
Dockerfile 指令
FROM 必须是第一条非注释命令,指定基础镜像。一个 Dockerfile 里可以多次 FROM 来构建多个镜像。不写 tag 默认用 latest。FROM scratch 从零构建。
FROM <image>:<tag>
RUN 在构建过程中执行命令并生成中间镜像层。中间层会被缓存,docker build --no-cache 可跳过缓存。
RUN <command> # shell 格式
RUN ["executable", "param1"] # exec 格式
把多条命令合并到一个 RUN 里能减少层数:
RUN apk update && apk add \
vim \
git \
curl
COPY 复制文件;WORKDIR 设工作目录,之后的 RUN/CMD/COPY 等都在该目录下执行(可叠加,docker run -w 可覆盖)。
EXPOSE 声明监听端口,但不会真的发布端口,要 docker run -p(指定映射)或 -P(随机映射)才生效。
EXPOSE 3000 80 443 22
VOLUME 创建挂载点;ENV 设环境变量(持续存在);ARG 设构建期变量(构建完即消失),docker build --build-arg name=value 传值。
ENV VERSION=1.0 DEBUG=on
ARG build_user="default user"
ENTRYPOINT 与 CMD 配合使用。区别在于 docker run 后跟的参数不会覆盖 ENTRYPOINT,而是作为参数传给它;CMD 指定的参数会被 docker run 的参数覆盖。docker run --entrypoint 可重写入口点。
一个完整的 Java 应用 Dockerfile 例子:
FROM openjdk:8-jdk-alpine
LABEL maintainer="<user>" version="1.0" name="Andrew Programming"
WORKDIR /
COPY target/dockerdemo1-0.0.1-SNAPSHOT.jar ./app.jar
VOLUME ["/data1"]
ENV VERSION=1.0
ARG build_user="Andrew programming"
EXPOSE 8080
# CMD 给 ENTRYPOINT 当默认参数,等价于 ENTRYPOINT ["java","-jar","/app.jar"]
CMD ["-jar", "/app.jar"]
ENTRYPOINT ["java"]
构建:
sudo docker build -t busybox:v1 . # 从当前目录 Dockerfile 构建
RUN 在构建时执行并生成新镜像,CMD 在容器运行时执行,构建时不做任何操作。