Docker
Basic Docker
Published: 2020-08-01

Docker基础知识,包括基础命令、Dockfile、网络模型等

虚拟机和容器的区别

虚拟机虽然达到了隔离的效果,但是它太庞大了,里面很多内容我们可能用不到,造成资源的浪费。

容器不需要装操作系统即可达到隔离效果

什么叫做互不影响的两套系统

有各自的id为1的进程(跟进程)

有FHS文件系统(文件根目录下有/etc等等的目录)

涉及到的有:

1、chroot(linux命令,用来切换根目录)

2、

3、

安装docker

Centos7环境下

Docker体系结构

Docker使用手册

使用docker --help可以查看docker的命令,包括登录登出harbor等命令都能找到

镜像操作

基础镜像拉取

机制

解释(看图里的序号):

  1. 使用pull等docker命令拉取镜像(这里可以理解为docker-client)

  2. 通过本地引擎查找本地是否存在该镜像,如果有则直接跳到第5步(这里的本地引擎可以理解为docker-server)

  3. 如果没有则通过ALi镜像加速到docker官方去下载这个镜像

  4. 将该镜像下载到本地镜像库

  5. 从本地镜像库找到目标镜像

  6. 用该镜像解压到相应的容器的位置变成一个只读的镜像层

  7. 在该镜像基础上写一些新的东西

  8. 将这个新的镜像作为一个整体打包(如果使用dockerfile其实就是在这个地方有多个镜像层一起打包)

  9. 将该新镜像通过commit命令存入本地镜像库

镜像基本查看

还可以按照镜像名来查找镜像:

$ docker image 镜像名
# 比方说:
$ docker image centos # 将会找出所有镜像名为"centos"的镜像

标识镜像唯一性

查看镜像详细信息

只查看镜像ID

镜像的导入和导出

镜像删除

如果镜像有依赖就用-f

删除所有镜像(用到上面“只查看镜像ID的命令”)

docker rmdocker rmidocker prune的差异

docker rm : 删除一个或多个 容器

docker rmi : 删除一个或多个 镜像

docker prune : 用来删除不再使用的 docker 对象

参考:https://www.cnblogs.com/miracle-luna/p/11111907.html(docker rm & docker rmi & docker prune 的差异)

给镜像打标签

容器操作

启动镜像

简写:

docker container run ID (这样的写法等同于docker container create imageId + docker container start containerId

但是这样写系统会给容器一个默认的名字,不太好区分,因此我们使用—name “名称” 选项手动指定:

交互式启动

加-it :docker container run -it ID

这里的i表示交互式,t表示开启一个新的终端

守护式启动

加-d :docker run -d ID

-d表示以后台daemon形式启动

这里我们本地并没有nginx这个东西但是他直接run也能启动起来,那是因为run的时候自动先pull,再run。

端口映射

宿主机外部也需要访问容器内的内容,这个时候需要加-p ip:port ,例如:

查看启动的容器

Docker container ls(或者docker ps)

Container ID

容器唯一号码(自动生成)

Names

容器的名字(可以自动生成,也可以手动指定)

Status

容器的运行状态(Exited, Up)

查看所有容器(包括启动的和退出的)

Docker container ls -a(或者docker ps -a)

查看容器详细信息

Docker container inspect 容器ID或者容器名称

这个命令可以查看容器的端口等详细信息,比如我们需要查看nginx的端口号那么就可以用这个命令

使用-f或者grep过滤

这个命令可以过滤出inspect显示的内容中Metadata对应的内容,当然,也可以使用grep Metadata -A 20来过滤

使用exit退出容器

退出容器之后我们查看所有容器发现之前退出的容器还是存在,导致我们无法创建同名容器,这个时候需要先删除这个容器。

(重点)另一种方法就是在启动镜像的时候添加–rm ,这样就不用再手动删除容器了

使用kill退出

暴力退出,一般数据库的退出不能使用kill,只能使用start、stop

容器的启动、关闭、连接

守护式容器

交互式容器

容器的连接方法

Attach

Attach的连接方法一个退出了就全部退出了

子进程方式登录(exec)

子进程方式登录的话一个ssh退出不会使得其他ssh退出,应用场景:nginx中添加页面,那么我们可以使用exec的方式进入添加页面之后再退出,达到添加了页面而不会使得其他ssh退出的效果

让容器永生的三种方法

比方说centos,启动centos的时候必定会占用一个终端窗口(由于终端窗口使用的是/bin/bash,因此如果不加-it启动容器会瞬间退出),那么当我们直接退出这个bash的时候容器也会退出,这不是我们想要的,那么可以这么做:

1、ctrl+p+q,将容器挂在后台,想要重连的时候使用attach即可;

2、容器启动的时候不加-it加sleep 100000,使得容器一直沉睡,达到容器一直存在的目的

3(重点)、以上两种方法了解即可,在应对守护式启动时,我们一般通过不加-d来让容器一直夯在前台达到永生

批量删除容器

模仿之前批量删除镜像,我们用到了-q去拿到所有镜像的ID,容器这里也一样

如果遇到容器依赖,使用-f

docker run -edocker run --env传递环境变量

假设有Dockerfile:

FROM openjdk:8-jdk-alpine
MAINTAINER fengqiangboy shenzhen <fengqiangboy@gmail.com>
RUN mkdir -p /usr/local/proxy-server
COPY startup.sh /usr/local/proxy-server
RUN cd /usr/local/proxy-server && \
chmod +x startup.sh
WORKDIR /usr/local/proxy-server
# 设置环境变量 USERNAME 默认值为 admin,后面可以通过docker run -e USERNAME="XXXXXX"修改,这个环境变量在容器里也可以$USERNAME获取
ENV USERNAME admin
RUN echo 'USERNAME=' $USERNAME  # 打印一下默认值
# 运行 startup.sh脚本,$USERNAME传递参数到脚本中,不能用 CMD []这种形式,这种方式读取不到变量
CMD sh startup.sh $USERNAME

假设startup.sh文件的内容如下:

#!/bin/bash

MODULE=$1  # 定义变量为上面传的 $USERNAME (第一个参数)
echo 'MODULE=' ${MODULE} # 打印

如果想替换参数使用命令sed -i "s/<USERNAME>/$USERNAME/" config.properties,必须用双引号,用单引号不能读取变量

假设查看最终文件目录如下:

[root@wanfei test-docker]# ls
Dockerfile  startup.sh

接下来制作镜像:

[root@root test-docker]# docker build -t www/test-docker .

运行镜像:

[root@root test-docker]# docker run --name docker -e USERNAME="QYF" www/test-docker
MODULE= QYF

打印成功 MODULE= QYF

使用docker save将指定镜像打包成tar归档文件

参考:https://www.runoob.com/docker/docker-save-command.html(docker save)

使用docker load导入使用docker save命令导出的镜像

参考:https://www.runoob.com/docker/docker-load-command.html(docker load)

使用docker update更新一个或多个容器的配置

参考:https://blog.lanweihong.com/posts/26195/(更新一个或多个容器的配置)、https://docs.docker.com/engine/reference/commandline/update/(官网docker update命令)

显示完整信息(–no-trunc)

这个命令可以显示完整ID号以及其他的一些显示不全的信息等

Docker网络

宿主机会开启一个docker0的网卡,容器启动的时候里面也会自动生成eth0网卡,容器和宿主机可以通过docker0通信。

容器网络映射

之前我们讲过容器端口映射

这里我们在同一个宿主机创建两个容器,我们发现他们是可以通过ip和端口互连的,但是外部还是不能连他们

宿主机8080端口映射到容器80端口

宿主机指定ip:port映射到容器80端口

宿主机随机ip:port映射到容器80端口

注意这里随机ip是0.0.0.0,port是从32768-60999依次向后

宿主机指定ip和随机port映射到容器80端口

注意这里的双冒号

一般情况下映射到容器tcp也可以指定udp

指定多端口映射

容器的其他命令

查看容器ID号

查看容器的进程情况

查看日志

这里的-t意思是显示得更全一些,-f意思是一直等待有新的日志情况然后显示,如果两个都不加那么就直接一次性显示之后就没了

Docker的数据卷实现持久化存储

容器默认位置

/usr/share

手工交互数据(Docker 的 cp 命令)

数据卷(Volume)

数据卷的另一个作用:做持久化,比方说MySQL,一个MySQL容器如果损坏或者删除的话那么这个容器所附带的数据也会跟着删除,那么就要做持久化操作,把它携带的数据、日志、配置文件等都通过数据卷持久化下来

查看数据卷的相关命令:

$ docker volume help

查看当前机器的docker的所有数据卷:

$ docker volume ls

创建新的数据卷:

$ docker volume create xxx

查看某个数据卷的具体信息:

$ docker container inspect volume01

查看容器的关键目录在宿主机挂载的路径

首先进入容器,然后使用命令docker container inspect 容器ID | grep Mounts -A 20

使用数据卷容器

当我们有大量的容器、大量的资源需要映射的时候,有一种方法是写多个-v

但是这个显然太麻烦,我们可以把这些映射定义为一个xyz容器,之后就挂这个容器就可以了

具体操作(–volumes-from)

作用:在集中管理集群中,大批量的容器都需要挂载相同的多个数据卷时,可以采用数据卷容器进行统一管理

案例(启动redis镜像的命令)

$ docker run -p 6379:6379 --name redis -v /usr/local/docker/redis.conf:/etc/redis/redis.conf -v /usr/local/docker/data:/data -d redis redis-server /etc/redis/redis.conf --appendonly yes

制作本地局域网yum源

下面两步看镜像制作那一块

更换运行中容器的配置文件

使用数据卷(volume)

一般情况下像nginx这种的会有负载均衡,也就是会有多台机器共同维持某个功能,这个时候可以使用数据卷修改配置,但是我们知道还需要重启容器才能达到更新配置的效果,由于有负载均衡,是可以做到部分机器重启而不影响服务器运行的,因此可以采用部分重启更新的策略去做服务器配置更新

镜像制作(类似于aliyun ECS)(这里模拟centos的,其他的也可以是特制的mysql等)

1、首先在宿主机挂载centos的iso文件(假设这个文件就是我们自己制作的,我们希望卖给别人,然后别人能够下载我们这个centos中的所有rpm而不需要去网络上下载,为了达到这个目的才有了下一步的替换yum源),一般将iso文件放在/mnt目录下,然后给宿主机设置开机自动挂载centos:

在/etc/rc.local/ 文件中设置如下:

需要验证的话就用:ftp://宿主机ip/,如果能访问到说明ok

2、然后为centos容器(这个容器是官方容器,我们想要在此基础上给容器加一些自己的东西)制作yum源:

先要进入centos容器,然后cd /etc/yum.repos.d/ 进入centos容器的yum源文件夹,可以看到有诸多源,将这些源全部挪到/tmp文件夹下

然后要使得容器能够访问到我们自制的yum源,配置如下:

然后执行命令:

yum clean all

yum makecache

3、下载ssh

Yum install -y openssh*(等价于yum install -y openssh-cli以及yum install -y openssh-server)

4、启动ssh服务

因为是6.9版本的centos,因此启动命令是:

/etc/init.d/sshd start

这里ssh第一次启动需要生成密钥对:

下次再起就不需要了:

注意这个密钥对一定要提前手动生成,不然下面的命令行启动sshd会出问题,也就是说这个sshd第一次启动一定是要我们人为的自己去启动,而不是用户去启动,而且必须要进入容器使用/etc/init.d/sshd start 命令去启动(针对centos6.9版本)

然后我们发现ssh有个机制就是必须要密码才能登录,那么我们再次回到centos容器(即用来模拟自己制作的容器),然后用passwd设置密码,之后再到宿主机使用ssh连接centos容器,我们会发现就可以连接上了,也就是说现在的容器已经具备了远程连接的能力

出现问题!

客户想要的是刚才这个centos6.9+ssh的这么一个东西,显然这个容器是不能宕掉的,bash窗口要一直存在,而且有个问题就是下次我把容器删掉了,一切都回到解放前,那么能不能把我们上面做的这一整个东西封装成我们自己的镜像呢?

基于容器的镜像制作

红线以上的命令事实上就是上面的一系列命令

由于是基于oldguo_sshv1容器制作的镜像,因此标准写法是:

Docker commit oldguo_sshv1 oldguo/centos6.9_sshd:v1

效果:

再次出现问题!

但是这个时候我们没有指定让容器启动之后开启ssh功能,而镜像只是一个静态资源,我们保存的镜像只是保存了多层文件系统,但是进程是动态的,无法将进程也保存进去,即容器是依赖镜像的动态资源,没有指定哪个文件先启动的话它是不会自己起的,所以我们现在就算开启了这个自制的镜像也不能使用其ssh

让sshd在前台启动(相当于一直夯在那)

使用命令 docker container run -d –-name=sshd -p 8080:80 ID号 /usr/sbin/sshd -D

如果使用命令:docker container run -d –-name=sshd ID号 /etc/initd/sshd start 我们会发现这个container的服务是exit状态的

**解释:**类似于linux系统中的1号进程,1号在那么整个系统就没有宕掉,而1号若不在了,就意味着它的所有子进程都会死掉,而/etc/init.d/sshd start 命令执行完之后我们会发现光标跳到新的一行去了,这意味着这个进程执行完了,那么就会死掉,也就导致了这样的启动方式之后容器其实是exit状态的。

构建企业网站定制镜像

启动基础镜像

注意:使用yum下载的centos的MySQL目录在/var/lib/mysql,html目录在/var/www/html(阿帕奇默认)

优化yum源

安装软件

软件初始化

制作LAMP第一版基础镜像

启用

测试php

上传bbs论坛安装文件到/var/www/html目录下并解压

制作第二版镜像

创建启动脚本

由于每次只能有一个启动类,但是我们又希望能将mysql、apache、sshd都起起来,并且最后让它夯在那,那只需要创建shell脚本并将sshd放到最后启动即可

基于centos7的制作

由于7版本软件服务的启动都由systemctl来控制,因此/etc/init.d/xxx start 这个命令就没有了,因此sshd的初始化需要手动完成,命令如下:

Dockerfile

FROM

非 ## 开头的第一句必须是FROM,然后有两种写法:

  1. FROM centos:6.9

  2. FROM centos@21999b8eb8390(推荐,不容易被黑客攻击)

第二句写RUN命令

每一行都会生成一个临时的容器,比方说在生成一个自制容器的时候第六行出错了,那么我们就可以到第五行的容器中调试,因此为了控制生成的临时容器的数量,我们尽量把shell命令用&符号拼接写到一行上

RUN

RUN命令在命令的前面会自动加一个/bin/sh -c,用这种方式来启动,这样的话RUN后面的这些命令它不是第一进程,必须以bash的方式去运行

对于RUN命令有针对shell和非shell的,

对于shell的就直接写好了,如:

,而针对非shell,这里举个MySQL的例子,写法:

注意它用[]包起来,其中命令本身“mysqld”用双引号包裹,后面 –- 开头的表示参数,也用双引号包裹,并用逗号分隔

事实上,非shell的命令更倾向于编写脚本然后最终在RUN中调用脚本

像这种情况,我们一般不把MySQL的启动写在RUN下,而是将类似这样的命令整合到CMD中的.sh脚本下,而且这样写更符合逻辑,因为创建镜像的时候本来就不用去启动服务的,而是到最后启动容器的时候才应该去开启服务

RUN命令可以起多个,当我们觉得这个容器生成到这个步骤之后需要打个断点并在此基础上再新起一个容器的时候就可以另起一行新起一个RUN命令,这样也方便之后的错误调试:

EXPOSE

暴露端口,如果有多个就分开写多行

CMD

之前我们启动容器,想要让它夯在那里,为此我们在命令最后一行加了:/usr/sbin/sshd -D

这样太麻烦,如果不想每次都这样加的话可以使用CMD命令:

CMD命令在生成最终镜像之前都不会执行,直到最后拿最终生成的镜像启动容器的时候才会执行。

注意它的写法,跟非shell命令一样,用[]和双引号包裹,用逗号分隔,且第一个是命令本身,后面的都是参数

CMD命令说明:

类似上面的RUN中MySQL的启动命令,这种中括号逗号的列表形式意味着将来启动该容器的时候这个命令就是1号进程,而不是先启动/bin/bash。

使用CMD执行容器中某个目录下的init.sh文件:

COPY

Copy命令将文件拷贝到容器中

注意 index.php这个文件必须要和dockerfile在同一目录下

假如目录不存在,容器会帮我们自动创建

COPY和ADD都支持通配符

大坑:如果拷贝的是目录,只拷贝目录下的子文件子目录

ADD

和COPY命令作用差不多,也是将文件拷贝进容器,但是如果传送的是tar型的压缩文件那么它还会帮我们自动解压

我们一般用ADD 多于用COPY,因为ADD功能更强大

ADD传输源文件有以下两个方法,且源文件可以有多个

传输本地文件

假如目录不存在,容器会帮我们自动创建

COPY和ADD都支持通配符

传输url

需要注意的是,传输的是url的前提下,如果内容是一个压缩包,那么它不会自动解压,只会传压缩包本身过去。

VOLUME

用于自动挂载卷,这里只指定了容器的数据卷目录,但是没指定宿主机的数据卷挂载目录,此时宿主机会指定一个默认的挂载目录来和容器的数据卷挂载目录对应,并且下次在启动另外一个容器的时候使用—volumes-from 参数调用这个容器,也可以使这个新起来的容器拥有跟我们制作的这个容器一样的数据卷,而且这两个容器的数据卷之间就是相关联的和宿主机也是相关联的。

WORKDIR

切换工作目录,有一个缺点就是一旦制定了这个参数,之后的所有dockerfile中的操作都是在这个目录下进行了,如果想换工作路径除非再手动声明绝对路径什么的,非常麻烦,所以一般我们用RUN cd去替代这个命令

ENV

定义环境变量,也可以用path定义环境变量,但是一般我们用ENV

这个时候我们如果想用/var/www/html的话直接用

${CODE_DIR}就可以了,如:

->

->

USER

切换用户

执行某个命令的时候是以什么样的身份

ONBUILD

比方说我们用dockerfile制作了镜像A,然后B镜像又要拿A去制作一个新镜像,这个时候会调用ONBUILD这个命令,用的不多。

ENTRYPOINT

和CMD类似,用处也是当我们拿这个镜像构建容器的时候会执行的命令

和CMD区别:

当我们只用了CMD的时候,在启动容器的时候理应执行CMD中的命令,但是如果我们在启动命令后面又加了一条命令,该命令就会替换掉CMD中的命令导致CMD中命令不再执行,如:

这里我们在最后又加了/bin/bash这个命令,那么启动的时候就会执行/bin/bash而不会执行CMD中的命令,这个时候可能就会出现容器不能夯在那里这样的情况:

而ENTRYPOINT的作用就是让命令无法替换,该运行谁还是运行谁,如:

这里把CMD用ENTRYPOINT替换,然后制作镜像

现在即使我们还是加了/bin/bash命令

/bin/bash还是不会执行,思考一下现在容器应该不会宕掉

高级用法

用来传参数用的,一般情况下不会使用

如下图中红圈圈部分现在可以手动敲一些参数,这些参数可以作为写在ENTRYPOINT中的entrypoint.sh脚本的参数

MySQL的docker就用到了这个高级用法,如:

ENTRYPOINT可以和CMD共用

LABLE

没啥用,就相当于注释,这里用作作者说明

调用dockerfile生成镜像

Docker image build -t “oldguo/centos6.9-sshd:v1.0” ./

最后的 ./ 是因为dockerfile就在当前目录下,这样写它会自动去找这个dockerfile

需要注意的是,我们一般会这样放置一个DockerFile:创建一个文件夹,放置DockerFile,以及这个DockerFile用于构建镜像所需要的所有其它文件,比方说构建一个jar服务的镜像,那它可能就会依赖一个jar包,那么此时这个jar包应该放到该DockerFile同一目录的文件夹下,目的是在构建镜像的时候将DockerFile上下文一起打包发给docker-server。

上面的红线标出的就是临时镜像,是可以进入的,如果第四步出错,我们将就可以进到第三步的容器中

问题

Dockerfile的using cache机制

如果dockerfile只发生了一小点改动,那么下一次再用这个dockerfile制作镜像的时候就会使用using file机制使得制作镜像的速度变得非常快

Dockerfile制作镜像时生成的临时镜像是否会占用大量磁盘空间

由于docker镜像是一种层级关系,一层依赖于一层,所以得出结论:

  1. 确实会占用空间,但是不多;

  2. 临时镜像不能随便删除(包括名称为none的镜像),因为存在依赖关系

本地yum源同步到阿里云

其实就是将阿里云的东西下载到本地,然后配置本地yum源,也就是那些repo即可

–restart=always解决服务重启导致容器全部退出

方法一

如果启动容器的时候没有加—restart=always这句话,当我们重启该服务的时候(这里以重启docker服务为例),我们会发现服务都宕掉了

这里加—restart=always表示不管你是主机重启还是服务重启还是docker重启,只要你起来就把我拉起来

之后我们再重启docker服务,发现这个容器还是开启状态的

方法二

在docker的json文件中添加“live-restore”: true

但是有些我不希望启动的容器比方说临时的容器也会被拉起来,这就是缺点

启动问题

解决ssh端口冲突

rm -rf .ssh即可

解决MySQL需要交互的问题

加参数-e即可

在RUN中的写法(针对5版本的MySQL):

RUN mysql -e “grant all on . to root@‘%’ identified by ‘123’;grant all on . to discuz@’%’ identified by ‘123’;create database discus charset utf8;”

例子

执行的时候发现 RUN mysql -e 这句命令失效了,进入临时容器调试发现是因为这条用于启动MySQL的RUN命令本身就是错误的,

我们发现MySQL命令前面加了/bin/sh -c 这个是执行shell命令用的,不能用于启动MySQL。解决方法是将启动MySQL的命令写到脚本里,再用RUN命令启动

我们将出问题的那一行RUN注释掉,然后将mysql创建用户命令写到init.sh中:

Docker构建私有registry

启动一个容器作为服务

修改docker的daemon.json配置文件

把上面的registry服务器的ip地址和端口写到配置文件中,使得下次pull镜像的时候可以从这个registry服务器中获取

重启docker服务

Systemctl restart docker

上传镜像到registry服务器

标准化镜像名称

Docker tag 原镜像名 标准化镜像名

标准化镜像名的格式为:

Registry的ip:registry的port/用作登录registry仓库的用户名/自定义仓库名:自定义标签名

Push命令

以前拉取镜像我们用的是pull,现在上传镜像用push

命令语法:

Docker push 标准化镜像名称

从registry服务器拉取镜像

命令语法:

Docker pull 标准化镜像名称

给本地仓库加安全验证

事实上就是给httpd生成密码

这个时候再push镜像会提示没有验证需要登录

Login命令

Docker login 服务器ip:服务器port

登录完之后才能继续push

浏览器访问registry

登录进取啥也看不到,应该是需要配置一些信息,但其实也没必要看这个

从加了安全验证的registry服务器拉取镜像

Pull不需要登录验证,直接就能pull

Harbor(重量版registry)实现图形化register

首先应该选择一台配置足够好磁盘空间足够多的机器来安装harbor

  1. 安装docker和docker-compose,yum install -y docker-compose

  2. 下载harbor-offline-installer-vxxx.tgz

  3. 上传到/opt并解压

  4. 修改harbor.cfg配置文件如下:

    hostname = 10.0.0.100

    harbor_admin_password = 123456

    (说明:其中hostname表示访问的域名,也是下面修改docker的daemon.json文件中的insecure-registries中需要添加的内容,如果不加的话会导致使用docker login登录的时候报错;

    Harbor_admin_password表示管理员登录密码)

  5. 执行install.sh

查看docker-compose版本

命令:docker-compose version

使用方法

解释一下为什么上图insecure-registries中10.0.0.100只写了ip没写port:因为它默认端口就是80,所以就不用写端口号了

而且由于harbor依赖的容器挺多的,因此设置“live-restore”:true,这样下次重启的时候就不需要手动去开启这些容器了

安装完之后会在服务器上起一些harbor相关的容器,这些容器来提供服务

安装之后会提示你用什么地址去访问

这个时候可能会报错提示端口被占用什么的,那么将被占用端口删除就可以了

之后登录:

用户名就是配置文件中的那个,这里是admin,密码也是配置文件中的密码,这里是123456

进入之后一般会先新建一个项目(项目名称其实就是当初10.0.0.100/oldboy/nginx:v1中的oldboy,如果这两个oldboy名称对应不起来会报错)

然后选择公开,公开的意思就是push的时候需要密码但是pull的时候不需要密码

当然,如果想登出docker harbor,可以使用命令docker logout username

启动、关闭和重启harbor

使用命令docker-compose start|stop|restart

推送镜像

跟上面的registry一模一样

之后harbor仓库里就会有镜像了

从harbor中pull

直接复制就行了,但是别的镜像也得修改daemon.json配置文件,之后才能使用

然后重启docker服务

之后把pull命令粘贴过来执行

删除操作

先删镜像再删仓库

更多说明

还有更多关于harbor.cfg的配置比如日志、仓库管理、配置管理、用户管理等,可以查百度

邮件设置,发送重置密码邮件时使用

在运行install.sh之前,配置harbor.cfg的时候修改:

Docker网络模型

宿主机网卡eth0安装完docker之后会有一个docker0网桥,默认网段地址就是172.17.0/16,是所有bridge,可以理解为容器的网关。Docker0的地址为172.17.0.1

然后我们起容器,docker会给这个容器分发一个eth0网卡且地址为172.17.0.2,这个时候docker0和容器里面会各自产生一个接口,容器通过这个接口指向docker0的接口(就像是交换机跟网线,容器一起来就相当于网线插到交换机,交换机的那个口子上的灯亮了一样)

这个时候容器就可以跟宿主机或者其他容器交互了(只要是在一个类型的网络下)

如果容器要对外访问,可以将请求丢给docker,使用docker提供的NAT功能通过宿主机的eth0出去来访问百度等外部网络(用的是内置的ipforward转发功能)

如果是外部访问内部容器,事实上是通过iptables指定转发规则,即将网卡为eth0的,端口8080的转发到端口80的容器等等(比方说eth0为10.0.0.100,端口为8080,转发到内部容器172.17.0.2:80,即需要通过iptables指定转发规则:10.0.0.100:80 -> 172.17.0.2:80而且该转发会经过docker0)

Docker作为bridge的注意点

Docker0只提供了容器之间的访问、容器与宿主机之间的访问以及容器的上网问题,但是没有提供外部访问容器的功能,该功能还是需要通过端口映射来完成,但是需要注意的是,外部访问容器还是需要经过docker的

查看支持网络类型

Docker network ls

测试使用各类网络类型

语法:docker run –network=xxx

none: 无网络模式

无网络就是没有网络

起的容器只有127的这个网卡,没法对外交互

bridge: 默认模式,相当于NAT(上面的几张图讲的就是这个)

上面的图讲的就是这种模式,单机模式下最常用的就是bridge模式

host: 共用宿主机Network NameSpace

性能最好,隔离最差

理念:只隔离部分资源,不隔离网络资源

和宿主机用同一个命名空间,使得该容器共用宿主机的ip、port、主机名等,但是它只是做了一部分功能,还是属于本地的一种网络模式,还上升不到全局的,全局的有更加复杂的设置方法。

使用该模式启动容器之后几乎无法和宿主机进行分辨,但是我们确定容器里面没有docker,所以敲一个docker命令就能分辨出到底是在容器里面还是在宿主机。

这种模式用的不多,因为隔离比较差,虽然挺方便的,因为外面访问进来和里面访问出去都只需要用宿主机的ip就可以了,端口的话自己指定(可想而知他的缺点就是如果一个机器起多个容器,那么他们的端口就不能重复,所以要做到端口的妥善管理),所以他也没有容器跨主机访问一说(容器本身就没有自己的网络隔离,用的就是宿主机的)。

而且包括hosts文件也是跟宿主机是一样的(下图是容器中的hosts文件)

在host模式的容器里启动sshd

由于这个时候容器跟宿主机用的是同一个ip,因此在容器内启动sshd是起不来的

那么怎么让他起来呢?

可以修改sshd的配置文件

我们把端口改2222

这个时候就能起来了,我们使用某一台宿主机用sshd去连他

发现是可以连进去的

container: 与其他容器公用Network Namespace

container在单机里面也很少见了。

host是跟主机共用网络空间(其他空间还是隔离的),container是容器之间共用网络空间,注意,这里ip和port都是共用的。

当我们启动一个容器的时候,会给这个容器开启一个网络空间,这个网络空间先来先得,也就是最先开启的容器会得到这个网络空间,那这个网络空间就算这个容器的,然后下次再开另一个容器的时候那个容器会和第一个容器共用该网络空间,再来一个也是一样,会共用第一个容器的网络空间。

该模式有特定的应用场景:比方说我起了一个容器,当他宕掉的时候有两种解决方法:

  1. 重启该容器;

  2. 新起一个容器,这个容器继承上一个容器的网络空间(ip、port等)

一般情况下我们如果使用上述方法二那我们就会用这种模式

这种模式在k8s中是常用的用来实现自愈功能的网络模型,但是在单机模式下该网络模式不常用

Docker跨主机网络介绍

需求背景:不想用k8s,只想简简单单的跨主机ping通两台宿主机中的容器

Macvlan

Docker自带的、轻量的

这种模式只能两个容器跨主机访问,但是两个容器都不能访问外网

建立一个通道让两台机器能够互相访问

创建步骤

在两个需要互联的宿主机上执行上述命令(相当于建立了一个通道)

然后两个机器再执行:

这里两个容器的ip的地址段要使用上面创建macvlan的时候写的地址段,这个—ip最好自己指定,不指定也行那就是他自动帮你分配,但是这样容易重复

这个macvlan_1是创建这个通道的时候取得名字

删除

语法:docker network delete macvlan名

有时候删不掉是因为有别的容器在使用他,这个时候用docker ps -a(其实就是docker container ls -a)命令配合grep筛选到目标容器然后先删掉这个容器之后即可删除该macvlan,然后别忘了两个容器中都开起了这个macvlan,因此还需要到另外一个容器里面删掉该macvlan

优点和缺点

优点是:

  1. 可以实现两个docker容器的跨主机访问;

缺点是:

  1. 不能访问外网

  2. 给两个容器起同一个ip地址macvlan是不会管的,比如说如果两个容器的ip都指定了100.0.0.10,这不会报错但是会导致同一个局域网里面会有两个相同的ip地址,这本是不被允许的。为了避免这种情况只能人工去管控他们的ip地址,这也是macvlan用的比较少的原因之一

因此引出了overlay模式

Overlay

其实就是在bridge模式的基础上加了一些东西,

首先跟bridge模式一样,每个容器都有自己的eth0,宿主机有docker0,内访外或者外访内都要通过docker0(反正就是跟bridge一样)

区别是他在容器内除了eth0还给了容器一张eth1网卡然后两个容器通过eth1网卡建立overlay通道互相访问

简单来讲就是给了容器一张对外访问的网卡和一张内部访问的网卡

解决macvlan的ip地址冲突问题

上图蓝箭头指向的容器就是用于记录两个宿主机使用网卡的情况,将使用过的网卡都记录下来统一配置管理,下次再用网卡的时候就看一下这个容器的记录,然后分一个新的网卡给它就好了

适用场景

他不像k8s这么重量级可以管理多台机器

这种模式就是少数几台机器的情况下既可以使得各自内部的容器互相访问又可以使得容器对外访问外网

启动步骤

启动consul服务,实现网络的统一配置管理

注意这个配置文件两边都要改(互相通信的两个docker的宿主机),改了之后才能被这个容器统一管理

这个consul就是上面所说的用于记录两个宿主机使用网卡情况的容器

上图的倒数第三句话(vim … docker.service)这个是新版本(18、19版本)需要改的,新版本需要改systemd的启动脚本,否则加了这个配置进去之后启动不了,如果是17版本的就不需要改这个

创建overlay网络

上面说到的eth1这个网卡走的就是上图—subnet 172.16.0.0/24 –-gateway 172.16.0.254这个子网。之后相当于创建了名为ol1的通道

查看这个容器

然后我们到另外一台宿主机上看docker network ls我们会发现虽然没有在这台机器上创建这个overlay,但是我们也能看到这个容器

两边启动容器测试

进去之后发现是可以ping通外网的,也可以ping通另一个容器