dockerfile + 源码 是原材料, image 是交付品, container 是运行示例
Install Docker Engine on Ubuntu | Docker Documentation
基于 EC2, Ubuntu 20.04
sudo apt install docker.io
# 手动进入容器
sudo docker run -it [IMAGE] /bin/bash
# 一些情况下 bash 不够用, 改为 sh
sudo docker run -it [IMAGE] /bin/sh
docker --help 检查所有命令
docker run [OPTIONS] IMAGE [COMMAND] [ARG……]
docker run hello-world
# -i 交互模式运行, -t 分配一个伪输入终端, 一般一起使用
docker run -it centos
docker run -it centos --name mycentos
# 启动终端并执行自定义命令
docker run -it centos npm run dev
# 后台运行, 不弹出交互窗口也不切换
# 后台运行必须有一个持续的进程, 不然就会自动退出
docker run -d
# 打开一个新终端, 运行 tomcat
# -p 将 8080 映射到 8080
# [外部 DOCKER PORT]:[内部 IMAGE PORT]
docker run -it -p 8080:8080 tomcat
# -P 随机分配端口, 启动后可能直接看不到端口, 需要 docker ps 来查看
docker run -P tomcat
docker ps
# 携带环境变量
docker run --env VAR1=value1 --env VAR2=value2 ubuntu
默认会下载 latest 版本, 可以带上特定的 tag: docker run hello-world: latest
hello-world
image, 如果有, 实例化产生 container 并运行# 列出本地所有镜像
docker images
# 列出本地所有镜像 包括中间层
docker images -a
# 列出本地所有镜像 ID
docker images -aq
# 到 dockerhub 搜索镜像关键字
docker search tomcat
# 删除一个本地的镜像, 但是如果有容器正在使用, 将不会删除
docker rmi hello-world
# 删除多个镜像
docker rmi a:latest b:latest c d e f
docker rmi -f ${docker ps -a -q}
# 删除容器, 注意不带 i 就是删除容器, 带了 i 就是删除镜像
docker rm
# 删除多个容器
docker rm -f ${docker ps -a -q}
docker ps -a -q | xargs docker rm
# 下载一个 image
docker pull centos
# 检查已经下载的 images
docker images
# 列出当前 docker 所有正在运行的 container, 注意不是 image
docker ps
# 列初当前正在运行的, 以及以前历史运行过的. 这个地方可以通过状态来识别是否已经在运行.
docker ps -a
# 列出上一次运行的 container
docker ps -l
# 列出最近 50 个 container
docker ps -n 50
# 退出容器, 终止容器并退出.
exit
# 不中止容器并退出
(Ctrl+P+Q)
docker start [CONTAINER/NAME]
docker restart [CONTAINER/NAME]
# 自然关闭
docker stop [CONTAINER/NAME]
# 强制停止
docker kill [CONTAINER/NAME]
# 查看日志, -t 包含时间戳, -f 跟随显示, --tail 默认尾部全部
docker logs -f -t --tail [CONTAINER]
docker logs -f -t --tail 3 [CONTAINER]
# 查看容器内运行的进程
docker top [CONTAINER]
# 查看容器内运行的细节
docker inspect[CONTAINER]
# 进入容器
docker attach [CONTAINER]
# 不进入容器就在容器中执行 ls -l /tmp, 并将结果返回宿主机
docker exec [CONTAINER] ls -l /tmp
# 将容器内的 /tmp/test.log 拷贝到宿主机的 /root 文件夹
docker cp [CONTAINER]: /tmp/test.log /root
# 注意结尾有一个点符号
docker build -t [IMAGE_NAME]:TAG .
# -f [DOCKER_FILE] 如果不添加的话就会自动寻找文件名为 DockerFile 的文件
docker build -f [DOCKER_FILE] -t [IMAGE_NAME]:TAG .
# 提交 container 副本令其成为一个新的 image
docker commit
# 列出镜像历史
docker history
镜像是一个 UnionFS (联合文件系统): 实际上是一种分层的, 高性能的, 轻量级的文件系统, 它支持对文件系统的修改作为一次提交来一层层叠加
一个 Image 可能引用了多个其他的镜像, 并且引用的镜像可以被多个 Image 引用 (类似 npm -g
的 模式)
一般来说, 容器里面产生的内容和数据在容器关闭之后会直接消失. 然后就需要将一些数据保存出来做持久化.
可以使用的方式:
# 如果对应的 path 没有会自动生成, 可以让 container 内部的一个 path 和外部 host 的一个 path 建立 binding
docker run -it -v [HOST_PATH]:[CONTAINER_PATH] [IMAGE]
# 添加多个 binding
docker run -it -v [HOST_PATH]:[CONTAINER_PATH] -v [HOST_PATH]:[CONTAINER_PATH] [IMAGE]
# 建立 binding 之后使用 inspect 可以从 HostConfig.Binds 里面找到
docker inspect [CONTAINER]
# 限定权限的模式, :ro 代表 read only
docker run -it -v [HOST_PATH]:[CONTAINER_PATH]:ro [IMAGE]
# 首先创建一个容器
docker run -it --name CONTAINER_1 [IMAGE]
# 然后在容器里面创建一些文件
# 根据相同的 Image 但是根据 CONTAINER_1 进行扩展
docker run -it --volumes-from CONTAINER_1 --name CONTAINER_2 [IMAGE]
随后两个 CONTAINER 里面会有相同的文件, 在其中任何一个 CONTAINER 里面修改会影响另一个
数据卷的生命周期持续到所有 CONTAINER 的引用消失为止
比如: 此时创建 CONTAINER_3, 然后做一些修改, 然后删除 CONTAINER_1 和 CONTAINER_2, CONTAINER_3 里面依然可以看到修改
使用 dockerfile 的主要的步骤:
可以看见在多数情况下,只有构建的时候会使用到这个 dockerfile
特性:
scratch
代表最原始的镜像CMD <Command>
CMD ["executable file", "arg1", "arg2", ……]
docker run
的时候运行这段 CMD 命令docker run [IMAGE]
就会默认执行最后一段 CMDdocker run [IMAGE] npm run dev
忽略原本 docker file 中的 CMD 并执行 npm run devCMD ["npm", "run","dev"]
随后想要在 docker run 的时候就无法给最后一段 CMD 添加额外参数 CMD ["npm", "start"]
+ docker run [IMAGE] -i
≠ CMD ["npm", "-i","start"]
ENTRYPOINT ["npm", "start"]
+ docker run [IMAGE] -i
= ENTRYPOINT ["npm", "-i","start"]
一个简单的 dockerfile:
FROM centos
VOLUME ["/folder1","/folder2"]
CMD echo "Done"
CMD /bin/bash
然后 build 一个新的 image
# 注意尾部有一个点用于当前目录
docker build -f [DOCKERFILE] -t [IMAGE_NAME] .
# 然后 docker run 跑起一个新的 container
# 新的 container 里面就会带上 folder1 和 folder2 两个目录
docker run -it [IMAGE]
# 需要注意的是, 就算这里没有使用 -v 来 bind host 的目录, docker 依然会生成一个目录用于数据持久化, 这个自动生成的逻辑只有通过 dockerfile 才会执行
FROM centos
ENV mypath /tmp # 设置一个环境变量
WORKDIR $mypath # 设置容器内的工作目录, 设定到 /tmp
RUN yum -y install vim
RUN yum -y install net-tools
EXPOSE 80
CMD /bin/bash
dockerFile1
FROM centos
ONBUILD RUN echo "this is father image" # 父镜像的 ONBUILD
假设使用上方 dockerfile 构建了一个镜像 centos1
: docker build -f dockerfile1 -t centos1 .
然后编写一个新的 dockerFile:
dockerFile2
FROM centos1 # 继承刚才创建的镜像
创建一个新的镜像: docker build -f dockerfile2 -t centos2 .
这个时候就会触发父镜像里面的 ONBUILD
加上一段参数即可
docker build -t hello-world ./ **--progress=plain --no-cache**