Docker 笔记

By | 2021年12月30日

Table of Contents

常用命令

# -i: 交互式操作,-t: 终端,这里是创建一个容器进入交互式终端
# --rm: 容器退出后将其删除,默认情况下,退出的容器并不会立即删除,除非手动 docker rm
docker run -it --rm ubuntu bash

# 拉取镜像(默认是 latest)
docker pull ubuntu
# 拉取指定版本镜像
docker pull ubuntu:16.04
# 列出镜像
docker image ls
# 根据名称和版本获取镜像ID(ubuntu:16.04)
docker image ls | grep ubuntu | grep 16.04 | awk '{print $3}'
# 删除镜像
docker image rm <Docker ID>
# 强制删除镜像,若镜像正在被使用,此命令很管用
docker image rm -f <Docker ID>

# TAG 标记为 <none> 的镜像,是由于新加镜像占用了原有镜像标签,原有镜像就变成了 <none> 镜像,这种叫空悬镜像(dangling images),这种已失去价值可删掉,下面命令只会删除悬空镜像,不会删除没有被容器使用的镜像。后面的 -f 参数表示"不提示确认",可有可无
docker image prune -f

# 查看镜像、容器、数据卷占用空间
docker system df

# 获取容器 mykafka 的 ID
docker container ls | grep 'mykafka' | awk '{print $1}'

# 使用内网代理构建镜像(Class 代理必须设为 Global 模式),这对 Dockerfile RUN 命令中下载被墙资源特别有用
# 执行构建前最好先测试下服务是否可用
telent 192.168.3.200 7890
# . 表示在当前 Dockerfile 目录下构建
docker build -t tomcat/wang:0.0.1 . --build-arg https_proxy=http://192.168.3.200:7890 --build-arg http_proxy=http://192.168.3.200:7890
# 导出镜像(推荐 gzip 导出)
docker save tomcat/wang:0.0.1 | gzip > tomcat-wang-0.0.1.tar.gz
docker save tomcat/wang:0.0.1 > tomcat-wang-0.0.1.tar
# 导入镜像
docker load < tomcat-wang-0.0.1.tar.gz

# /var/lib/docker/overlay2 占满磁盘救星:删除关闭的容器、无用的数据卷和网络以及无tag的镜像
docker system prune
# 将没有容器使用 Docker 镜像都删掉。注意,这个命令会把暂时关闭的容器,没有用到的镜像都删了
docker system prune -a

# 显示容器资源的使用情况,包括:CPU、内存、网络 I/O 等
docker stats

# 遇坑记:容器内测试其他网站 API 是否可用时,若参数有 &,需要前面加 \ 来转义
docker exec -it <ContainerID> bash -c "curl http://feepolicy:8080/solr/select?q=id_device:*\&api_token=xyz

# 查看容器IP(需进容器)
cat /etc/hosts

# Docker 容器日志默认位置
cat /var/lib/docker/containers/<container_id>/<container_id>-json.log

Docker 事件

# 从服务器获取实时事件,仅返回最后 1000 个日志事件
docker events  --since="1467302400"

官方参考

Docker 引擎安装

官方教程:Debian 安装Ubuntu 安装CentOS 安装装后指导

注意:RedHat7.5或CentOS7执行 “sudo yum install docker-ce” 如果报如下错
———————————
Error: Package: 3:docker-ce-18.09.0-3.el7.x86_64 (docker-ce-stable)
Requires: container-selinux >= 2.9
You could try using –skip-broken to work around the problem
You could try running: rpm -Va –nofiles –nodigest
———————————

则需要安装:
$ sudo yum install -y http://mirror.centos.org/centos/7/extras/x86_64/Packages/container-selinux-2.55-1.el7.noarch.rpm

卸载旧版本

$ sudo yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-selinux docker-engine-selinux docker-engine

切换到国内yum软件源(可选)

$ sudo yum install -y yum-utils device-mapper-persistent-data lvm2
$ sudo yum-config-manager –add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

阿里云源:https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
官方源:https://download.docker.com/linux/centos/docker-ce.repo
中科大开源镜像站:mirrors.ustc.edu.cn

如果需要最新版本的 Docker CE 请使用以下命令(这里我没有开启):
$ sudo yum-config-manager –enable docker-ce-edge

安装 Docker CE

$ sudo yum makecache fast
$ sudo yum install docker-ce

这里执行”yum makecache fast” 即使使用阿里云镜像服务后还是会报错:
https://download.docker.com/linux/centos/7/x86_64/stable/repodata/repomd.xml: [Errno 12] Timeout on 正在尝试其它镜像。

因此我直接翻墙,从官网下载 package 包到 /mnt/来安装了,
$ sudo yum install /mnt/docker-ce-18.03.1.ce-1.el7.centos.x86_64.rpm

但还是报上面的错误,真是蛋疼,这个 repomd.xml 必须翻墙才能访问。
解决办法,网上找到一篇文章(没有实践,因为不知道什么原因,我重新 yum-config-manager –add-repo 后得到的 docker-ce.repo 里的 baseurl是阿里云的了,可能之前repo太多,后来都被我删了):
不知为何,阿里云与USTC镜像站上默认的docker-ce.repo文件内部地址均是指向docker官方站https://download-stage.docker.com 这样导致直接下载下来的repo文件无法正常使用,需要将baseurl修改为国内镜像站的地址。
$ sudo vim /etc/yum.repos.d/docker-ce.repo
# sed -i ‘s@https://download-stage.docker.com/linux/centos/7/@https://mirrors.aliyun.com/docker-ce/linux/centos/7/@g’ /etc/yum.repos.d/docker-ce.repo
# sed -i ‘s@https://download-stage.docker.com/linux/centos/gpg@https://mirrors.aliyun.com/docker-ce/linux/centos/gpg@g’ /etc/yum.repos.d/docker-ce.repo

使用脚本自动安装

在测试或开发环境中 Docker 官方为了简化安装流程,提供了一套便捷的安装脚本,CentOS 系统上可以使用这套脚本安装:
$ curl -fsSL get.docker.com -o get-docker.sh
$ sudo sh get-docker.sh –mirror Aliyun
执行这个命令后,脚本就会自动的将一切准备工作做好,并且把 Docker CE 的 Edge 版本安装在系统中。

启动 Docker CE(安装好后,默认是Disabled的)

$ sudo systemctl enable docker
$ sudo systemctl start docker

建立 docker 用户组

一般要使用 sudo 来执行docker命令,如果将当前用户加入docker组,就不需要使用 sudo了。

默认情况下,docker 命令会使用 Unix socket 与 Docker 引擎通讯。而只有 root 用户和 docker 组的用户才可以访问 Docker 引擎的 Unix socket。出于安全考虑,一般 Linux 系统上不会直接使用 root 用户。因此,更好地做法是将需要使用 docker 的用户加入 docker 用户组。
建立 docker 组:
$ sudo groupadd docker
将当前用户加入 docker 组:
$ sudo usermod -aG docker $USER
查看当前用户是否已经加入 docker 组:
$ cat /etc/group |grep docker
退出当前终端并重新登录,进行如下测试。

镜像

配置镜像加速器、更改默认存储目录

国内从 DockerHub 拉取镜像较慢,可配置镜像加速器,例如:

科大镜像:https://docker.mirrors.ustc.edu.cn/
网易:https://hub-mirror.c.163.com/
阿里云:https://<你的ID>.mirror.aliyuncs.com
七牛云加速器:https://reg-mirror.qiniu.com

可以多添加几个国内的镜像,如果有不能使用的,会切换到可以使用的镜像来拉取。
之前还有 Docker 官方加速器 https://registry.docker-cn.com/,现在好像已经不能使用了。

对于使用 systemd 的系统(如:Ubuntu16.04+、Debian8+、CentOS7),请在 /etc/docker/daemon.json 中写入如下内容(如果文件不存在请新建该文件):

{
	"registry-mirrors": ["https://docker.mirrors.ustc.edu.cn/", "https://hub-mirror.c.163.com/"],
	"data-root": "/home/docker"
}

上面 data-root 设置将 docker 的默认存储位置 /var/lib/docker 改到了 /home/docker。
加好后重新启动服务:

sudo systemctl daemon-reload
sudo systemctl restart docker

检查加速器是否生效:

docker info

若在最后看到下面这段就说明生效了:

 Registry Mirrors:
  https://docker.mirrors.ustc.edu.cn/
  https://hub-mirror.c.163.com/

在更多操作系统上配置镜像加速,可参考 Docker 镜像加速

用 docker image ls 命令来配合

docker image ls 还支持强大的过滤器参数 --filter,或者简写 -f。比如,我们希望看到在 mongo:3.2 之后建立的镜像,可以用下面的命令:
$ sudo docker image ls -f since=mongo:3.2

--filter配合-q产生出指定范围的 ID 列表,然后送给另一个 docker 命令作为参数,从而针对这组实体成批的进行某种操作的做法在 Docker
命令行使用过程中非常常见,不仅仅是镜像,将来我们会在各个命令中看到这类搭配以完成很强大的功能。
因此每次在文档看到过滤器后,可以多注意一下它们的用法。

比如,我们需要删除所有仓库名为 redis 的镜像:
$ sudo docker image rm $(docker image ls -q redis)
或者删除所有在 mongo:3.2 之前的镜像:
$ sudo docker image rm $(docker image ls -q -f before=mongo:3.2)

配置 direct-lvm 给 devicemapper

  • 在 Ubuntu/Debian 上有 UnionFS 可以使用,如 aufs 或者 overlay2,而 CentOS 和 RHEL 的内核中没有相关驱动。
    因此对于这类系统,一般使用 devicemapper 驱动利用 LVM 的一些机制来模拟分层存储。这样的做法除了性能比较差外,稳定性一般也不好,而且配置相对复杂。
    Docker 安装在 CentOS/RHEL 上后,会默认选择 devicemapper,但是为了简化配置,其 devicemapper 是跑在一个稀疏文件模拟的块设备上,也被称为 loop-lvm。
    这样的选择是因为不需要额外配置就可以运行 Docker,这是自动配置唯一能做到的事情。
    但是 loop-lvm 的做法非常不好,其稳定性、性能更差,无论是日志还是 docker info 中都会看到警告信息。
    官方文档有明确的文章讲解了如何配置块设备给 devicemapper 驱动做存储层的做法,这类做法也被称为配置 direct-lvm。
  • 除了前面说到的问题外,devicemapper + loop-lvm 还有一个缺陷,因为它是稀疏文件,所以它会不断增长。用户在使用过程中会注意到
    /var/lib/docker/devicemapper/devicemapper/data 不断增长,而且无法控制。
    很多人会希望删除镜像或者可以解决这个问题,结果发现效果并不明显。
    原因就是这个稀疏文件的空间释放后基本不进行垃圾回收的问题。因此往往会出现即使删除了文件内容,空间却无法回收,随着使用这个稀疏文件一直在不断增长。
  • 所以对于 CentOS/RHEL 的用户来说,在没有办法使用 UnionFS 的情况下,一定要配置 direct-lvm 给 devicemapper,无论是为了性能、稳定性还是空间利用率。

可参考:
https://www.cnblogs.com/SZLLQ2000/p/5486834.html
https://www.cnblogs.com/zhangzihong/p/6611319.html

慎用 docker commit

使用 docker commit 制作镜像意味着所有对镜像的操作都是黑箱操作,生成的镜像也被称为黑箱镜像,换句话说,
就是除了制作镜像的人知道执行过什么命令、怎么生成的镜像,别人根本无从得知。实际环境中并不会这样使用。

使用 Dockerfile 定制镜像

FROM 指定基础镜像。
RUN 指令是用来执行命令行命令的。由于命令行的强大能力,RUN 指令在定制镜像时是最常用的指令之一。
之前说过,Dockerfile 中每一个指令都会建立一层,RUN 也不例外。因此为了一个目的而是用多个RUN是不对的,这会构建好多层。应该使用&&,如:
RUN buildDeps=’gcc libc6-dev make’ && && apt-get update && && apt-get install -y $buildDeps。
在撰写 Dockerfile 的时候,要经常提醒自己,这并不是在写 Shell 脚本,而是在定义每一层该如何构建。

Docker 还存在一个特殊的镜像,名为 scratch。如果你以 scratch 为基础镜像的话,意味着你不以任何镜像为基础,接下来所写的指令将作为镜像第一层开始存在。
这不是什么罕见的事,使用 Go 语言 开发的应用很多会使用这种方式来制作镜像,这也是为什么有人认为 Go 是特别适合容器微服务架构的语言的原因之一。

翻墙

如果是在虚拟机上制作,则除了主机需要翻墙,虚拟机的网路需要设置为 “NAT模式:用于共享主机的IP地址”。

构建镜像

  • 镜像构建上下文(Context)
    $ sudo docker build -t nginx:v3 .
    2)一般来说,应该会将 Dockerfile 置于一个空目录下,或者项目根目录下。如果该目录下没有所需文件,那么应该把所需文件复制一份过来。
    如果目录下有些东西确实不希望构建时传给 Docker 引擎,那么可以用 .gitignore 一样的语法写一个 .dockerignore,
    该文件是用于剔除不需要作为上下文传递给 Docker 引擎的。
  • 直接用 Git repo 进行构建或许你已经注意到了,docker build 还支持从 URL 构建,比如可以直接从 Git repo 中构建:$ sudo docker build https://github.com/twang2218/gitlab-ce-zh.git#:8.14 这行命令指定了构建所需的 Git repo,并且指定默认的 master 分支,构建目录为 /8.14/,然后 Docker 就会自己去 git clone 这个项目,切换到指定分支,并进入到指定目录后开始构建。
  • 用给定的 tar 压缩包构建 “$ sudo docker build http://server/context.tar.gz”,如果所给出的 URL 不是个 Git repo,而是个 tar 压缩包,那么 Docker 引擎会下载这个包,并自动解压缩,以其作为上下文,开始构建。
  • 从标准输入中读取 Dockerfile 进行构建:sudo docker build – < Dockerfile 或 $ sudo cat Dockerfile | docker build -,如果标准输入传入的是文本文件,则将其视为 Dockerfile,并开始构建。这种形式由于直接从标准输入中读取 Dockerfile 的内容,它没有上下文,因此不可以像其他方法那样可以将本地文件 COPY 进镜像之类的事情。
  • 从标准输入中读取上下文压缩包进行构建:$ sudo docker build – < context.tar.gz,如果发现标准输入的文件格式是 gzip、bzip2 以及 xz 的话,将会使其为上下文压缩包,直接将其展开,将里面视为上下文,并开始构建。

多阶段构建

(1)多阶段构建允许在Dockerfile中使用多个FROM指令。两个FROM指令之间的所有指令会生产一个中间镜像,最后一个FROM指令之后的指令将生成最终镜像。
中间镜像中的文件可以通过COPY --from=<image-number>指令拷贝,其中image-number为镜像编号,0为第一个基础镜像。
没有被拷贝的文件都不会存在于最终生成的镜像,这样可以减小镜像大小。

(2)FROM指令可以使用as <stage-name>来指定步骤名称(stage name):FROM maven:3.5-jdk-8 as BUILD。
这样的话,COPY指令的--from选项可以使用步骤名称代替镜像编号。
Dockfile 示例:
———————————-
FROM maven:3.5-jdk-8 as BUILD
COPY src /usr/src/myapp/src
COPY pom.xml /usr/src/myapp
RUN mvn -f /usr/src/myapp/pom.xml clean package
FROM jboss/wildfly:10.1.0.Final
COPY –from=BUILD /usr/src/myapp/target/people-1.0-SNAPSHOT.war /opt/jboss/wildfly/standalone/deployments/people.war
———————————-

(3)当我们只想构建 BUILD 阶段的镜像时,我们可以在使用 docker build 命令时加上--target参数即可
$ docker build --target BUILD -t username/imagename:tag .

上面例子中我们使用COPY --from=BUILD从上一阶段的镜像中复制文件,我们也可以复制任意镜像中的文件。
$ COPY --from=nginx:latest /etc/nginx/nginx.conf /nginx.conf

把运行中的容器里的配置拷贝到宿主机器上

$ docker run --name tmp-nginx-container -d nginx
$ docker cp tmp-nginx-container:/etc/nginx/nginx.conf /host/path/nginx.conf
$ docker rm -f tmp-nginx-container

ENTRYPOINT/CMD

(1)经测试,子镜像的添加 ENTRYPOINT,会覆盖父镜像的 ENTRYPOINT

(2)CMD命令在Docker容器每次启动时都会执行,如果使用了 CMD[“docker-entrypoint.sh”],那么这个 docker-entrypoint.sh 每次容器启动都会被执行。

ENTRYPOINT的 exec 与 shell 形式

ENTRYPOINT 有两种形式:

ENTRYPOINT ["executable", "param1", "param2"] (exec形式,首选的)
ENTRYPOINT command param1 param2 (shell形式)
  • exec形式
    例如,下面命令启动 nginx: docker run -i -t --rm -p 80:80 nginx
    docker run <image> 的命令行参数将附加在 exec形式入口点中的所有元素之后,并将重写使用CMD指定的所有元素。
    这允许将参数传递到到 entrypoint(entrypoint.sh)。
  • shell形式
    shell形式禁止使用任何CMD和 run命令行参数。缺点是你的 ENTRYPOINT 将被作为 /bin/sh -c 的子命令启动,这将无法传递 signals。这意味着可执行文件将不是容器的PID 1,且不能接受 Unix signals,也就是说你的可执行文件无法收到 docker stop <container> 的 SIGTERM。如果需要为单个可执行文件编写启动脚本,可以使用exec和gosu命令确保最终可执行文件接收到UNIX信号。

最后,如果您需要在关闭时执行一些额外的清理(或与其他容器通信),或者需要协调多个可执行文件,那么您可能需要确保 ENTRYPOINT 脚本接收Unix信号,传递它们,然后再执行一些其他工作

ENV 环境变量 

制作镜像时,我们可以使用 ENV设置环境变量,如:
ENV INFLUXDB_DATA_MAX_VALUES_PER_TAG=0
查看容器内的所有环境变量:docker exec -it 14d env
也可以进入容器后使用:echo $INFLUXDB_DATA_MAX_VALUES_PER_TAG

容器

介绍

应该保证在一个容器中只运行一个进程。将多个应用解耦到不同容器中,保证了容器的横向扩展和复用。例如 web 应用应该包含三个容器:web应用、数据库、缓存。

如果容器互相依赖,你可以使用 Docker 自定义网络 来把这些容器连接起来。

每一个容器运行时,是以镜像为基础层,在其上创建一个当前容器的存储层,我们可以称这个为容器运行时读写而准备的存储层为容器存储层。

容器不应该向其存储层内写入任何数据,容器存储层要保持无状态化。所有的文件写入操作,都应该使用 数据卷(Volume)、或者绑定宿主目录,在这些位置的读写会跳过容器存储层,直接对宿主(或网络存储)发生读写,其性能和稳定性更高。数据卷的生存周期独立于容器,容器消亡,数据卷不会消亡。因此,使用数据卷后,容器删除或者重新运行之后,数据却不会丢失。

docker run 后台运行的过程

(1)检查本地是否存在指定的镜像,不存在就从公有仓库下载
(2)利用镜像创建并启动一个容器
(3)分配一个文件系统,并在只读的镜像层外面挂载一层可读写层
(4)从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去
(5)从地址池配置一个 ip 地址给容器
(6)执行用户指定的应用程序
(7)执行完毕后容器被终止

查看容器

# 查看运行的容器
docker container ls   
# 查看运行的和终止的容器                  
docker container ls -a
# 查看指定容器的详细信息
docker inspect <containerID>
# 获取容器IP
docker exec <containerID> cat /etc/hosts
# 获取容器 mykafka 的 ID
docker container ls | grep 'mykafka' | awk '{print $1}'

运行一个容器

$ docker run --name mybash -it --rm centos bash

接着,我们查看下这个centos7的系统版本信息吧:
# cat /etc/os-release
# exit

-it:这是两个参数,一个是 -i:交互式操作,一个是 -t 终端。我们这里打算进入 bash 执行一些命令并查看返回结果,因此我们需要交互式终端。
--rm:这个参数是说容器退出后随之将其删除。默认情况下,为了排障需求,退出的容器并不会立即删除,除非手动 docker rm。

注:如果制作镜像时改变了默认的root用户,启动容器时想要以root登录,请使用下面命令:
$ docker exec -it --user root 46c bash

终止容器

$ docker stop mybash //”mybash”是容器的名称,也可以用容器的Container ID(前3位即可)
提示:当 Docker 容器中指定的应用终结时,容器也会自动终止。
例如对于镜像章节中只启动了一个终端的容器,用户通过 exit 命令或 Ctrl+d 来退出终端时,所创建的容器立刻终止。

启动已终止容器

$ docker start mybash
$ docker restart mybash
容器的核心为所执行的应用程序,所需要的资源都是应用程序运行所必需的。除此之外,并没有其它的资源。可以在伪终端中利用 ps 或 top 来查看进程信息:
$ ps
——————————–
PID TTY TIME CMD
1 pts/0 00:00:00 bash
11 pts/0 00:00:00 ps
——————————–
可见,容器中仅运行了指定的 bash 应用。这种特点使得 Docker 对资源的利用率极高,是货真价实的轻量级虚拟化。

仅输出一个完整的容器ID

$ docker run -d centos sh -c “while true; do echo 你好; sleep 1; done”
运行上面的命令,仅输出一个完整的容器ID:
f6c499928a9e3a38772cd4e4fffc8293fc02a761874226646848f742db597611

添加参数-d后,容器会在后台运行并不会把输出的结果打印到宿主机上面(输出结果可以用 docker logs 查看)。
$ docker logs f6c

进入容器

在使用 -d 参数时,容器启动后会进入后台。某些时候需要进入容器进行操作(如在 bash 下输入命令),
包括使用 docker attach 命令或 docker exec 命令,推荐大家使用 docker exec 命令。
$ docker exec -it mybash bash
$ exit
如果从这个标准输入中 exit,不会导致容器的停止。这就是为什么推荐大家使用 docker exec 的原因。

导出/导入

(1)镜像导出再导入
$ docker export mybash > mybash.jar
这样将导出容器快照到本地文件。可以使用从容器快照文件中再导入为镜像,例如:
$ docker import mybash.jar wanghua/mybash:v2
这会从镜像归档文件 mybash.jar 创建镜像,命名为 wanghua/mybash:v2。
(2)通过指定 URL 或者某个目录来导入
$ docker import http://example.com/exampleimage.tgz example/imagerepo
(3)注:用户既可以使用 docker load 来导入镜像存储文件到本地镜像库,也可以使用 docker import 来导入一个容器快照到本地镜像库。
这两者的区别在于容器快照文件将丢弃所有的历史记录和元数据信息(即仅保存容器当时的快照状态),而镜像存储文件将保存完整记录,体积也要大。
此外,从容器快照文件导入时可以重新指定标签等元数据信息。

删除容器

# 删除终止的容器
docker rm <containerID> 
# 删除运行中的容器
docker rm -f <containerID>
# 用 docker container ls -a 命令可以查看所有已经创建的包括终止状态的容器,
# 如果数量太多要一个个删除可能会很麻烦,用下面的命令可以清理掉所有处于终止状态的容器
docker container prune

直接执行容器 Linux Shell 脚本

docker exec -it <containerID> bash -c "tail -n 1 /kafka/log4j-logs/server.log"

网络

Docker的4种网络模式

原文地址:https://www.cnblogs.com/gispathfinder/p/5871043.html

host 网络(net=host)

(1)如果使用host网络,那么不需要使用”-p 3306::3306″这种了,用了也会被忽略。
(2)macbook上直接装docker
macbook上直接装docker,在run镜像时不能用 --net=host模式,因为对应端口3306等无法访问,必须使用 “-p 3306:3306” 才行。

经测试,由于运行 fastdfs的 tracker和storage时,storage连接tracker似乎必须用 --net=host模式,所以也没办法。

目前的解决方案:在macbook上装个虚拟机跑centos7,再在centos7里运行docker。

bridge 网络(net=bridge)

bridge是默认设置,docker的桥接不是桥接到主机的wifi等,而是自己会创建一个 docker0 网桥。当Docker server启动时,会在主机上创建一个名为docker0的虚拟网桥,此主机上启动的Docker容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。我发现这个 docker0 默认放通了所有出去的包,因为 我能将日志数据存到 主机192.168.1.220 的kafka上。

简介Busybox是一个集成了一百多个最常用Linux命令和工具的软件工具箱,它在单一的可执行文件中提供了精简的Unix工具集。

$ docker network create -d bridge fal-net
$ docker run -it --rm --name busybox1 --network fal-net busybox sh
$ docker run -it --rm --name busybox2 --network fal-net busybox sh

下面通过 ping 来证明 busybox1 容器和 busybox2 容器建立了互联关系。在 busybox1 容器输入以下命令:
/ # ping busybox2
注意:以上只能在容器内互联,如果还要让宿主主机或外网可以访问,可以添加 -p,如:
$ docker run -d --name falmongo -p 27017:27017 --network fal-net mongodock

此时使用宿主主机的:”localhost”、”127.0.0.1″、”192.168.1.83″来连,192.168.1.83下面会讲到。

注: -p 可以写多次,如:docker run -d --name falmongo -p 27017:27017 -8080:8080 --network fal-net mongodock

overlay 网络(用于swarm中)

overlay 网络驱动程序在多个 Docker 守护进程主机之间创建一个分布式网络。这个网络在允许容器连接并进行安全通信的主机专用网络之上(overlay 覆盖在上面)。Docker 透明地处理每个 Docker 守护进程与目标容器之间的数据包的路由。

当初始化 swarm 集群或将一个 Docker 主机加入已经存在的 swarm 集群时,Docker 主机上会创建两个新网络:
(1)一个称为ingress的 overlay 网络,用来处理与 swarm 服务相关的控制和数据流。当创建的 swarm 服务没有连接到用户自定义的 overlay 网络时,这个服务会默认连接到 ingress 网络。
(2)一个称为docker_gwbridge的bridge 网络,用来将单个的 Docker 守护进程连接到 swarm 中的其他守护进程。

可以使用docker network create命令创建用户定义的 overlay 网络,就像可以创建用户定义的 bridge 网络一样。服务或容器一次可以连接到多个网络。服务或容器只能通过它们各自连接的网络进行通信。

默认情况下,容器不能借助宿主主机的IP和端口访问另一个容器

$ docker run -d --name falmongo -p 27017:27017 mongo

此时在宿主主机(192.18.1.202)用”studio-3t-5.4.0-linux-x64″客户端连接mongodb,用”localhost”、”127.0.0.1″、”192.168.1.83″都可以访问,但是用
192.18.1.202就不行,这个地址是我自己配置的static地址。192.168.1.83是 dynamic ens33,使用”ip addr”可以看到:
———
宿主主机(192.18.1.202):ip addr 发现有个”192.168.1.83″。
link/ether 00:0c:29:c9:e4:3a brd ff:ff:ff:ff:ff:ff
inet 192.168.1.83/24 brd 192.168.1.255 scope global noprefixroute dynamic ens33
valid_lft 82270sec preferred_lft 82270sec
inet 192.18.1.202/24 brd 192.18.1.255 scope global ens33
———
注:但是在其他容器中,借助宿主的IP 192.168.1.83 访问就访问不了,但是可以ping通 192.168.1.83(结论:默认情况下,容器不能借助宿主主机的IP和端口访问另一个容器,除非-p映射
注:宿主主机是虚拟机,虚拟机装在我的win10上,经测试,win10也可以通过 192.168.1.83 访问容器的mongodb。
————————————————————————–

宿主机和容器、容器和容器之间都可以互相ping通

比如tomcat容器的地址是 192.168.1.2,宿主主机地址是 192.168.1.3,且我们设置了 -p 8060:8080,此时用 http://192.168.1.2:8080 和 http://192.168.1.3:8060 都可以访问。
如果容器使用自定义网络,默认情况下,宿主机和容器之间无法ping通,容器与容器之间可以ping通。

外部访问容器

容器中可以运行一些网络应用,要让外部也可以访问这些应用,可以通过 -P 或 -p 参数来指定端口映射。
当使用 -P 标记时,Docker 会随机映射一个 49000~49900 的端口到内部容器开放的网络端口。

-p 则可以指定要映射的端口,并且,在一个指定端口上只可以绑定一个容器。支持的格式有 ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort。

$ docker run -d -p 5000:5000 training/webapp python app.py //映射所有接口地址
$ docker run -d -p 127.0.0.1:5000:5000 training/webapp python app.py //映射到指定地址的指定端口
$ docker run -d -p 127.0.0.1::5000 training/webapp python app.py //映射到指定地址的任意端口
$ docker run -d -p 127.0.0.1:5000:5000/udp training/webapp python app.py //还可以使用 udp 标记来指定 udp 端口
$ docker port mybash 5000 //查看映射端口配置
$ docker run -d -p 5000:5000 -p 3000:80 training/webapp python app.py //-p 标记可以多次使用来绑定多个端口

容器互联

如果你有多个容器之间需要互相连接,推荐使用 Docker Compose。

下面先创建一个新的 Docker 网络 my-net。
$ docker network create -d bridge my-net
-d 参数指定 Docker 网络类型,有 bridge overlay。其中 overlay 网络类型用于 Swarm mode,在本小节中你可以忽略它。

运行一个容器并连接到新建的 my-net 网络
$ docker run -it --rm --name busybox1 --network my-net busybox sh

打开新的终端,再运行一个容器并加入到 my-net 网络
$ docker run -it --rm --name busybox2 --network my-net busybox sh

再打开一个新的终端查看容器信息

下面通过 ping 来证明 busybox1 容器和 busybox2 容器建立了互联关系。
在 busybox1 容器输入以下命令
/ # ping busybox2

创建自定义网络,指定网段fal-net(192.168.0.0/16),默认是 bridge

$ docker network create --subnet=192.168.0.0/16 fal-net
$ docker network ls

配置网络一:192.168.1.151(mongo)

$ docker run -d --name falmongo -p 27017:27017 --network fal-net --ip 192.168.1.151 mongo
$ docker exec -it mongo bash

配置网络二:192.168.1.152(faltomcat)

$ docker run --name faltomcat -p 8090:8090 --network fal-net --ip 192.168.1.152 faltomcat:0.0.1
$ docker exec -it faltomcat bash

————————————————————————–
(1)容器允许外部访问,可以在 docker run 时候通过 -p 或 -P 参数来启用。不管用那种办法,其实也是在本地的 iptable 的 nat 表中添加相应的规则。
因此要使用 -p 或 -P参数,宿主主机必须开启iptable(centos7中用:service firewalld start)
(2)宿主主机内的Docker之间可以互相ping通。比如,我们进入tomcat容器,ping 192.168.1.152,默认就能ping通mongo容器。关闭宿主主机的firewalld后也能ping通。
———————————————
我们无法将文件复制到tomcat容器的 /user/local/下,但能安装到容器当前目录下,例如可以拷贝到 /user/local/tomcat/tools/,这应该是权限问题,可以使用sugo。
Python 进程管理工具 Supervisor 建议装下
———————————————

link

我们在使用Docker的时候,经常可能需要连接到其他的容器,比如:web服务需要连接数据库。按照往常的做法,需要先启动数据库的容器,映射出端口来,然后配置好客户端的容器,再去访问。其实针对这种场景,Docker提供了--link参数来满足。
(1)启动mysql服务
$ docker run -d -P --name=mysql_server mysql:5

(1)启动客户端容器,连接mysql
$ docker run -it --name=mysql_client1 --link=mysql_server:db hzc/mysql_client mysql -h db -uroot -p123456

注意:可以看到多了一个参数配置--link=mysql_server:db, 是告诉当前容器需要使用mysql_server容器,并命名为db。这里db就是mysql_server容器的别名。
在后面连接数据库的时候是可以直接使用mysql -h db -uroot -p1234来连接mysql数据库。

仓库

Docker Hub

Docker Hub为用户提供不限数目的公开镜像托管服务,但仅提供一个私有镜像托管服务。
(1)Docker Registry 公开服务是官方的 Docker Hub,这也是默认的 Registry。一般这类公开服务允许用户免费上传、下载公开的镜像。
国内的一些云服务商提供了针对 Docker Hub 的镜像服务(Registry Mirror),这些镜像服务被称为加速器,常见的有 阿里云加速器。
(2)除了使用公开服务外,用户还可以在本地搭建私有 Docker Registry。Docker 官方提供了 Docker Registry 镜像,可以直接使用做为私有 Registry 服务。
开源的 Docker Registry 镜像只提供了 Docker Registry API 的服务端实现,足以支持 docker 命令,不影响使用。但不包含图形界面,以及镜像维护、用户管理、访问控制等高级功能。在官方的商业化版本 Docker Trusted Registry 中,提供了这些高级功能。除了官方的 Docker Registry 外,还有第三方软件实现了 Docker Registry API,甚至提供了用户界面以及一些高级功能。比如,VMWare Harbor 和 Sonatype Nexus。
(3)根据是否是官方提供,可将镜像资源分为两类。
一种是类似 centos 这样的镜像,被称为基础镜像或根镜像。这些基础镜像由 Docker 公司创建、验证、支持、提供。这样的镜像往往使用单个单词作为名字。
还有一种类型,比如 tianon/centos 镜像,它是由 Docker 的用户创建并维护的,往往带有用户名称前缀。

Pull 镜像

$ docker pull wanghuadocker/nginx:v4

Push 镜像(需要先登录)

用户也可以在登录后通过 docker push 命令来将自己的镜像推送到 Docker Hub,如:
$ docker login -u wanghuadocker -p solution
$ docker tag nginx:v4 wanghuadocker/nginx:v4 //要push到 Docker Hub,必须先调整镜像的命名规范:username/镜像名:版本
$ docker push wanghuadocker/nginx:v4
$ docker search wanghuadocker //push上去后,这个命令搜不到,可能使用了镜像加速器的缘故吧,但是可以 pull 到
$ docker logout
$ docker pull wanghuadocker/nginx:v4
注:也可以推送到阿里云,具体百度下吧。

自动创建(具体实践参见 自动构建笔记)

有时候,用户创建了镜像,安装了某个软件,如果软件发布新版本则需要手动更新镜像。
而自动创建允许用户通过 Docker Hub 指定跟踪一个目标网站(目前支持 GitHub 或 BitBucket)上的项目,一旦项目发生新的提交或者创建新的标签(tag),Docker Hub 会自动构建镜像并推送到 Docker Hub 中。
要配置自动创建,包括如下的步骤:
创建并登录 Docker Hub,以及目标网站;
在目标网站中连接帐户到 Docker Hub;
在 Docker Hub 中 配置一个自动创建;
选取一个目标网站中的项目(需要含 Dockerfile)和分支;
指定 Dockerfile 的位置,并提交创建。
之后,可以在 Docker Hub 的 自动创建页面 中跟踪每次创建的状态。

Nexus3.x 的私有仓库

在企业中把内部的一些工具包放入 Nexus 中是比较常见的做法,最新版本 Nexus3.x 全面支持 Docker 的私有镜像。
所以使用 Nexus3.x 一个软件来管理 Docker , Maven , Yum , PyPI 等是一个明智的选择。

其他

docker system

$ docker system df // 类似于Linux上的df命令,用于查看Docker的磁盘使用情况
$ docker system prune // 清理磁盘,删除关闭的容器、无用的数据卷和网络,以及dangling镜像(即无tag的镜像)
$ docker system prune -a // 此命令清理得更加彻底,可以将没有容器使用Docker镜像都删掉。注意,这两个命令会把你暂时关闭的容器,以及暂时没有用到的Docker镜像都删掉了
注:使用 docker system prune -a 清理后,重新创建的镜像可以连接 mongo容器了,奇怪!

显示地址和路由

# ip addr show docker
# ip route show

容器调度(Swarm)

以Docker的方式来运行容器[15]意味着一个容器是短暂存在的,并且每一个容器只运行一个进程。根据这条原则,多个容器提供一个服务或者代表一个应用是极度正常的。
因此编排和调度容器成为了最应当解决的问题,这也解释了为什么,即便这项技术不是很成熟,但仍有那么多的调度器被开发出来,并且提供了不同的功能和选项。

如果你已经拥有一个Mesos 集群,Mesos & Marathon将会是一个完美的组合方案。它能够像其他Mesos框架一样调度行任务,同时拥有一个类似于Docker Compose的描述文件来制定任务,这些特性使得它成为在集群上运行容器的极佳方案。Mesosphere[45]提供的完整解决方案同样也是一个适合生产环节的、简单而强大的方式。

相比于Swarm,Mesos的容错性更强,这是因为Mesos能够在JSON文件中对某个应用使用监看检查。因为自动扩展功能是商业版独有的,因此这里集群并不能自动扩展,但是我们还是有其他的办法来实现它,比如说Amazon EC2 Auto Scaling Groups。

管理敏感数据

docker secret
通过以上方法,我们没有像以前通过设置环境变量来设置 MySQL 密码, 而是采用 docker secret 来设置密码,防范了密码泄露的风险。
注意: secret 也可以在 Docker Compose 中使用。

管理配置数据(config 仅能在 Swarm 集群中使用)

在动态的、大规模的分布式集群上,管理和分发配置文件也是很重要的工作。传统的配置文件分发方式(如配置文件放入镜像中,设置环境变量,volume 动态挂载等)都降低了镜像的通用性。
在 Docker 17.06 以上版本中,Docker 新增了 docker config 子命令来管理集群中的配置信息,以后你无需将配置文件放入镜像或挂载到容器中就可实现对服务的配置。

安全

建议采用专用的服务器来运行 Docker 和相关的管理服务(例如管理服务比如 ssh 监控和进程监控、管理工具 nrpe、collectd 等)。其它的业务服务都放到容器中去运行。

注意点

CMD脚本的权限

WORKDIR

环境变量

rw和ro

Docker nginx 中使用非80端口映射proxy_set_header的使用

nginx中的80删除后记得-p不能用80

FQA

执行下面命令时,报错:file integrity checksum failed

$ docker save centos7-jdk8-tomcat8-tools-python27-falpos | gzip>centos7-jdk8-tomcat8-tools-python27-falpos.tar.gz
这个问题不知道什么原因,用 docker system prune -a 删除所有镜像再重新导入后解决了此问题。

Error response from daemon: OCI runtime create failed: container_linux.go:345: starting container process caused “process_linux.go:430: container init caused \”write /proc/self/attr/keycreate: permission denied\””: unknown

需要修改seliunx模式,把/etc/selinux/config里面的SELINUX值修改为disabled,然后保存重启。

There is insufficient memory for the Java Runtime Environment to continue.Cannot create GC thread. Out of system resources.

这个问题出现在改用支持 ARM 的镜像 storm:1.2.4-temurin 后,且仅出现在统信操作系统中。CentOS7 中没有出现过。

解决办法:Container Fails to Start: Insufficient memory for the Java Runtime Environment to continue,在 compose yaml 中加这个就好了:

装了 Docker 的 Ubuntu 系统在 ufw 防火墙上配置 SNAT 为何不起作用?

Docker 会默认直接加规则到 iptables,所以 UFW 防火墙对 docker 无效,可以执行 iptables -L 命令查看。

服务器断电致 Docker 引擎起不来

错误信息:

8月 02 09:11:28 zeepolicy dockerd[11810]: time="2023-08-02T09:11:28.814060391+08:00" level=warning msg="could not use snapshotter devmapper in metadata plugin" error
8月 02 09:11:28 zeepolicy dockerd[11810]: time="2023-08-02T09:11:28.814079659+08:00" level=info msg="metadata content store policy set" policy=shared
8月 02 09:11:28 zeepolicy dockerd[11810]: panic: invalid page type: 29: 10

解决办法:将 daemon.json 中设置的 data-root 的文件夹给删了(推荐重命名),不指定的话默认位置应该是 /var/lib/docker。然后重启 docker 就好了,但此时 docker 中安装的镜像都没了。

Portainer可视化界面

Portainer是Docker的图形化管理工具,提供状态显示面板、应用模板快速部署、容器镜像网络数据卷的基本操作(包括上传下载镜像,创建容器等操作)、事件日志显示、容器控制台操作、Swarm集群和服务等集中管理和操作、登录用户管理和控制等功能。本人一直用命令,没用过这款工具,所以这里只是介绍下而已。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注