个人学习笔记,摘抄自 https://yeasy.gitbook.io/docker_practice
文章目录
docker 简介
Docker 使用 Google 公司推出的 Go 语言 进行开发实现,基于 Linux 内核的 cgroup,namespace,以及 OverlayFS 类的 Union FS 等技术,对进程进行封装隔离,属于 操作系统层面的虚拟化技术。由于隔离的进程独立于宿主和其它的隔离的进程,因此也称其为容器。
基本概念
- 镜像
Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。 镜像使用分层存储的结构, 且可以继承复用的。 - 容器
容器是镜像运行时的实体,可以被创建、启动、停止、删除、暂停等。容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的命名空间。容器也是分层存储的,每个容器运行时以镜像为基础创建当前的容器存储层。容器存储层的生存周期和容器一样,容器消亡时,容器存储层也随之消亡。 - 仓库
Docker Registry是一个集中的存储、分发镜像的服务。我们可以通过 <仓库名>:<标签> 的格式来指定具体是这个软件哪个版本的镜像。仓库名经常以 两段式路径 形式出现,比如 jwilder/nginx-proxy,前者往往意味着 Docker Registry 多用户环境下的用户名,后者则往往是对应的软件名。
使用镜像
修改国内镜像源
mac: 在 Perferences -> Docker Engine 中添加以下配置, 再选择应用和重启就好了。
{
"registry-mirrors": [
"https://hub-mirror.c.163.com",
"https://mirror.baidubce.com"
]
}
**linux
- 使用
systemctl cat docker
查看 ExecStart= 的位置,修改对应文件内容。 - 编辑
/etc/docker/daemon.json
,输入上面的内容。 - 重启
sudo systemctl daemon-reload
sudo systemctl restart docker
使用镜像
获取镜像
docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签]
默认仓库地址: Docker Hub (docker.io)
仓库名:<用户名>/<软件名>, 所谓的用户名可以理解为项目组的东西,默认是 library
例如: docker pull ubuntu:18.04
运行
以 ubuntu:18.04
为例. 如果需要启动里面的bash并且镜像交互操作的话,可执行
docker run -it --rm ubuntu:18.04 bash
参数解释:
-it
:-i 进行交互式操作, -t 终端--rm
: 容器退出后即删除,这里实验用,所以直接删掉节约空间。ubuntu:18.04
: 使用指定的镜像为基础启动容器bash
: 放在镜像后的命令,使用 bash 进行交互。
列出镜像
查看镜像(默认显示顶层镜像)
docker image ls
其他拓展查询
# 查询 ubuntu 的镜像
docker image ls ubuntu
# 查询指定镜像
docker image ls unbuntu:18.04
# 过滤镜像, mongo:3.2之后的, before 之前
docker image ls -f since=mongo:3.2
# 根据label过滤
docker image ls -f label=com.example.version=0.1
由于镜像的分层结构,且能够继承复用,实际空间比列出的所有空间要小。
查看镜像/容器/数据卷占用空间命令为
docker system df
无标签的镜像被称为虚悬镜像,一般虚悬镜像已经失去了价值,可以随意删除的。删除命令
docker image prune
删除镜像
docker image rm [选项] <镜像1> [<镜像2> ...]
镜像可以是 镜像短id、镜像长id、镜像名、镜像摘要
删除过程
- untagged:取消标签,由于镜像的分层结构,一个镜像可以对应多个标签,只有镜像没有任何标签时才回被删除
- deleted:真正删除镜像, 如果镜像启动的容器还在,也不会删除,容器是基于镜像的。
使用 docker image ls 配合批量删除
docker image rm $(docker image ls -q redis)
commit
将容器的存储层保存下来成为镜像。
但是不要使用commit定制镜像,应使用Dockerfile完成。
docker commit [选项] <容器ID或容器名> [<仓库名>[:<标签>]]
示例:
docker commit \
--author "作者" \
--message "修改了默认网页" \
webserver \
nginx:v2
修改容器后,可以用 docker diff 容器名
查看具体改动。
使用docker commit
意味着所有对镜像的操作都是黑箱操作,生成的镜像也被称为黑箱镜像. 非常不利于维护。且对容器镜像的修改只是在当前层镜像标记、添加、修改,不会修改上层。使用commit会使得镜像很臃肿。
Dockerfile
镜像的定制实际上就是定制每一层所添加的配置、文件,因此将这些操作写入一个脚本,就能解决前面说的透明、体积的问题。
Dockerfile包含了一条条的 指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。
示例: 定制nginx镜像,修改index.html
FROM nginx
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
FROM
指定基础镜像。且必须指定一个基础镜像,如服务类 nginx、redis、mongo、mysql、httpd、php、tomcat, 语言类 node、openjdk、python、ruby、golang,系统类 ubuntu、debian、centos、fedora、alpine。 空白镜像 scratch。RUN
执行命令。 两种格式- shell 格式,
RUN <命令>
- exec 格式,
RUN ["可执行文件", "参数1", "参数2"]
- shell 格式,
一个示例:
FROM debian:stretch
RUN set -x; buildDeps='gcc libc6-dev make wget' \
&& apt-get update \
&& apt-get install -y $buildDeps \
&& wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \
&& mkdir -p /usr/src/redis \
&& tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 \
&& make -C /usr/src/redis \
&& make -C /usr/src/redis install \
&& rm -rf /var/lib/apt/lists/* \
&& rm redis.tar.gz \
&& rm -r /usr/src/redis \
&& apt-get purge -y --auto-remove $buildDeps
因为每个指令都会构建一层,所以通过 && 将所有命令串联起来,简化构建。且示例中最后一行删除类为了编译构建所需要的软件,将无关的东西清理掉,不然会一直跟着镜像。
另Dockerfile 支持 \ 进行换行,# 注释。
定制镜像
docker build [选项] <上下文路径/URL/->
如在 Dockerfile文件所在命令执行:
docker build -t nginx:v3 .
关于上下文路径:
上面例子构建的上下文路径为.
,这个是表示将当前目录作为上下文路径。Docker运行时分为Docker引擎(服务端)和客户端,使用REST API镜像交互(所以还能操作远程服务端)。而构建镜像时docker build
会将路径下的所有内容打包上传给Docker引擎。 Dockerfile中可以通过相对路径
访问这些文件。 另外也可以使用.dockerignore
剔除不需要作为上下问传递给Docker引擎。 默认构建文件为上下文路径中的 Dockerfile
,也可以 -f 指定其他文件。
其他构建方式
# 使用ulr构建,如git仓库 master分支,amd64/hello-word 目录
docker build` -t hello-world https://github.com/docker-library/hello-world.git#master:amd64/hello-world
# 使用tar压缩包构建
docker build http://server/context.tar.gz
# 从标准输入读取Dockerfile
docker build - < Dockerfile
或
cat Dockerfile | docker build -
# 标准输入读压缩包
docker build - < context.tar.gz
Dockerfile 指令
-
FROM
指定基础镜像 -
RUN
执行命令. 详见 Dockerfile -
COPY
复制文件- 从上下文目录中复制文件到镜像中,源路径可多个,支持通配符。两种格式:
COPY [--chown=<user>:<group>] <源路径>... <目标路径>
COPY [--chown=<user>:<group>] ["<源路径1>",... "<目标路径>"]
- 源文件元数据保留,如读写权限。
- –chown 可改变文件所属用户&组
- 源文件为文件夹,则复制文件夹下的内容到目标路径
- 从上下文目录中复制文件到镜像中,源路径可多个,支持通配符。两种格式:
-
ADD
高级复制- 格式基本和 COPY 一致
- 源路径支持url,默认权限600,修改权限或解压需另用RUN
- 源文件为tar时(格式 gzip,bzip2,xz),支持自动解压
- 不实用,不建议使用。会时构建缓存失效,构建变慢。
-
CMD
容器启动命令- 两种格式:
- shell:
CMD <命令>
- exec:
CMD ["可执行文件", "参数1", "参数2"...]
。 推荐这个模式,shell最终还是解析成这样 - 参数列表格式:
CMD ["参数1", "参数2"...]
。在指定了 ENTRYPOINT 指令后,用 CMD 指定具体的参数。
- shell:
- 用于指定默认的容器主进程的启动命令。docker不是虚拟机,容器就是进程,所以需要启动命令。
- docker run后面的执行命令优先级比这个高
- 容器不是虚拟机,应用都是前台执行,无后台服务概念。对于容器而言,其启动程序就是容器应用进程,容器就是为了主进程而存在的,主进程退出,容器就失去了存在的意义,从而退出。
- 错误示例:
CMD service nginx start
解释;sh为主进程,sh执行完就退出了,且没有后台进程。 - 正确使用:
CMD ["nginx", "-g", "daemon off;"]
- 错误示例:
- 两种格式:
-
ENTRYPOINT
入口点- 目的和 CMD 一样,都是在指定容器启动程序及参数。略繁琐
- 指定 ENTRYPOINT 后,CMD 不再直接运行,而且作为产生传递给 ENTRYPOINT, 实际执行变为
<ENTRYPOINT> "<CMD>"
(主要利用cmd作为参数这点使用) - 如 docker run 后面 CMD 可以当作参数,可以利用这个在执行docker run时指定参数, 让镜像变成像命令一样使用
-
ENV
设置环境变量- 格式:(有空格加引号)
-ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2>...
- 支持的指令:ADD、COPY、ENV、EXPOSE、FROM、LABEL、USER、WORKDIR、VOLUME、STOPSIGNAL、ONBUILD、RUN
- 格式:(有空格加引号)
-
ARG
构建参数- 效果同 ENV, 但只在构建时生效,容器运行后不生效。 但在docker history中可以看到所有值
- 构建命令 docker build 中可用 --build-arg <参数名>=<值> 来覆盖对应的值。 1.13版前-arg的参数必须Dockerfile中指定
- FROM 会分割 ARG 的生效范围。 FROM 后面的指令读取不到ARG,需重设
-
VOLUME
定义匿名卷- 格式:
VOLUME ["<路径1>", "<路径2>"...]
VOLUME <路径>
- 容器运行时动态数据文件应保存与卷中。可以事先指定某些目录挂载为匿名卷,这样在运行时如果用户不指定挂载,其应用也可以正常运行,不会向容器存储层写入大量数据
- 运行时可覆盖
docker run -d -v mydata:/data xxxx
mydate 命名卷挂载到/data上了,替代了匿名卷的配置
- 格式:
-
EXPOSE
暴露端口- 格式:
EXPOSE <端口1> [<端口2>...]
- 仅声明,不会自动在宿主进行端口映射. 运行时使用
-p <宿主端口>:<容器端口>
才是将容器的对应端口服务公开给外界访问。
- 格式:
-
WORKDIR
指定工作目录- 指定工作目录后,后续各层的当前目录都是指定的目录。 (由于
分层结构
每个指令都是处于不同的容器中,连续的两个指令的当前目录也就不连续了)。 Dockerfile不是shell
- 指定工作目录后,后续各层的当前目录都是指定的目录。 (由于
-
USER
指定当前用户- 格式:
USER <用户名>[:<用户组>]
- USER 指令和 WORKDIR 相似,都是改变环境状态并影响以后的层。 用户需是已存在的。 如需再执行期间切用户,建议使用gosu(需要下载)
- 格式:
-
HEALTHCHECK
健康检查- 格式:
HEALTHCHECK [选项] CMD <命令>
:设置检查容器健康状况的命令HEALTHCHECK NONE
:如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令
- 告诉docker如何判断容器状态是否正常, 1.12新增指令。 (容器内死锁的情况Docker不能自行判断)
- 参数:
--interval=<间隔>
默认30s;--timeout=<时长>
超时时间 30s;--retries=<次数>
重试次数
- 格式:
-
ONBUILD
特殊指令- 格式:
ONBUILD <其他执行>
- 后面跟的是其它指令,比如 RUN, COPY。只有作为基础镜像构建下一级镜像时才被执行
- 格式:
-
LABEL
元数据LABEL <key>=<value> <key>=<value> <key>=<value> ...
- 可以用来声明镜像作者,文档地址等
-
SHELL
SHELL ["executable", "parameters"]
- 可以指定 RUN ENTRYPOINT CMD 指令的 shell,Linux 中默认为 ["/bin/sh", “-c”]bu
操作容器
新建并启动
如启动一个bash终端,并进行交互
docker run -t -i ubuntu:18.04 /bin/bash
-t
分配一个伪终端并绑定到容器的标准输入上,-i
打开容器的标准输入
当利用 docker run 来创建容器时,Docker 在后台运行的标准操作包括:
- 检查本地是否存在指定的镜像,不存在就从公有仓库下载
- 利用镜像创建并启动一个容器
- 分配一个文件系统,并在只读的镜像层外面挂载一层可读写层
- 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去
- 从地址池配置一个 ip 地址给容器
- 执行用户指定的应用程序
- 执行完毕后容器被终止
后台运行
添加 -d
参数
此时可以通过获取容器的输出信息
docker container logs <container ID or NAMES>
终止容器
docker container stop <id or names>
查询终止状态容器
docker container ls -a
重启命令
- start 重启一个已停止的容器
- restart 重启运行中的容器
进入容器
attach
命令docker attach <id>
, exit后容器会停止
exec
docker exec -it <id>
-it 分配伪终端,和命令提示符
导入和导出
-
docker export <id>
到处容器快照- 如:
docker export xxxx > ubuntu.tar
- 如:
-
docker import
将容器快照文件导入为镜像- 如:
cat ubuntu.tar | docker import - test/ubuntu:v1.0
- 或使用url:
docker import http://example.com/exampleimage.tgz example/imagerepo
- 如:
删除
删除处于终止状态的容器
docker container rm <id>
清理所有终止状态的容器
docker container prune
访问仓库
拉取镜像
docker search <name>
搜索镜像docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签]
推送镜像
首先需要先登陆一下,然后输入用户名和密码。(如果用的公有仓库需要先去 https://hub.docker.com 注册一个账号)
docker login
# 退出
docker logout
然后推送镜像
docker tag ubuntun:18.04 <username>/ubuntu:18.04
docker push <username>/ubuntu:18.04