一、安装docker

1.安装必要的一些系统工具

[root@docker ~]# yum -y install yum-utils device-mapper-persistent-data lvm2
#yum-utils管理repository及拓展包的工具;
#其他两个存储驱动程序所需;

2.添加软件源信息

[root@docker ~]# yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

3.更新查看版本并安装docker

[root@docker ~]# yum makecache fast
[root@docker ~]# yum list docker-ce.x86_64 --showduplicates | sort -r
[root@docker ~]# yum -y install docker-ce-18.09.0 docker-ce-cli-18.09.0

4.开启docker服务

[root@docker ~]# systemctl start docker
[root@docker ~]# systemctl enable docker

5.设置docker镜像加速器
在阿里云平台即可找到镜像加速器配置步骤。

[root@docker ~]# mkdir -p /etc/docker
[root@docker ~]# tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://sbba7wvp.mirror.aliyuncs.com"]
}
EOF
[root@docker ~]# systemctl daemon-reload
[root@docker ~]# systemctl restart docker

6.配置路由转发给功能

[root@docker ~]# vim /etc/sysctl.conf
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
[root@docker ~]# sysctl -p
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1

二、底层原理

如果虚拟机内服务对内核版本有要求,那这个服务就不适合用docker来实现。
内核版本要求为3.10以上版本。
镜像是容器运行的基石,容器是镜像运行之后的实例。
相关概念

Busybox:欺骗层(模拟不同系统的根目录);

解耦:解除耦合、冲突;

耦合:冲突现象;

普通虚拟化:完全型解耦;

Docker:半解耦;

在这里插入图片描述
Namespace(名称空间)
namespace六项隔离,实现了容器与宿主机、容器与容器之间的隔离。

逻辑空间------->隔离
用来隔离容器。

/proc、/sys:虚拟文件系统,伪目录文件----->内存
[root@docker ns]# pwd
/proc/4/ns
[root@docker ns]# ll
总用量 0
lrwxrwxrwx 1 root root 0 8月  26 01:33 ipc -> ipc:[4026531839]
lrwxrwxrwx 1 root root 0 8月  26 01:33 mnt -> mnt:[4026531840]
lrwxrwxrwx 1 root root 0 8月  26 01:33 net -> net:[4026531956]
lrwxrwxrwx 1 root root 0 8月  26 01:33 pid -> pid:[4026531836]
lrwxrwxrwx 1 root root 0 8月  26 01:33 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 8月  26 01:33 uts -> uts:[4026531838]

名称解释

IPC:共享内存、消息列队;

MNT:挂载点、文件系统;

NET:网络栈;

PID:进程编号;

USER:用户、组;

UTS:主机名、域名;

cgroup(控制组)
限制docker容器对宿主机资源的使用。

[root@docker cgroup]# pwd
/sys/fs/cgroup
[root@docker cgroup]# ls
blkio    cpu,cpuacct  freezer  net_cls           perf_event
cpu      cpuset       hugetlb  net_cls,net_prio  pids
cpuacct  devices      memory   net_prio          systemd
[root@docker cgroup]# cd cpu
[root@docker cpu]# ls
cgroup.clone_children  cpuacct.usage         cpu.rt_runtime_us  system.slice
cgroup.event_control   cpuacct.usage_percpu  cpu.shares         tasks
cgroup.procs           cpu.cfs_period_us     cpu.stat           user.slice
cgroup.sane_behavior   cpu.cfs_quota_us      notify_on_release
cpuacct.stat           cpu.rt_period_us      release_agent
[root@docker cpu]# cat tasks
1
2
4
...

tasks文件内的数字,记录的是进程编号PID。
cgroup的四大功能

(1)资源限制:可以对进程组使用的资源总额进行限制。

(2)优先级分配:通过分配的cpu时间片数量以及硬盘IO带宽大小,实际相当于控制了进程运行的优先级别。

(3)资源统计:可以统计系统资源使用量,比如cpu使用时间、内存使用量等,用于按量计费,还支持挂起功能。
也就是说通过cgroup把所有资源限制起来,对资源都不能使用,注意这并不是说我们的程序不能使用了,只是不能使用资源,处于等待状态。

(4)进程控制:可以对进程组执行挂起、恢复等操作。

内存限额
容器内存包括两个部分:物理内存和swap。
可以通过参数控制容器内存的使用量。

-m或者--memory:设置内存的使用限额;

--memory-swap:设置内存+swap的使用限额;

示例:运行一个容器,并且限制该容器最多使用200M内存和100M的swap。

[root@docker ~]# docker run -itd --name container1 -m 200MB --memory-swap 300MB centos:7
8e8da890b10bb5a309bba53658ba2f7334ae4380b5873a9ff87ac5501c135401
[root@docker ~]# cd /sys/fs/cgroup/memory/docker/8e8da890b10bb5a309bba53658ba2f7334ae4380b5873a9ff87ac5501c135401/
[root@docker 8e8da890b10bb5a309bba53658ba2f7334ae4380b5873a9ff87ac5501c135401]# cat memory.limit_in_bytes
209715200
[root@docker 8e8da890b10bb5a309bba53658ba2f7334ae4380b5873a9ff87ac5501c135401]# cat memory.memsw.limit_in_bytes
314572800

对比一个没有限制的容器,如果运行容器之后不限制内存的话,则认为没有限制。
CPU使用
通过-c或者–cpu-shares设置容器使用cpu的权重。如果不设置默认为1024。
示例

[root@docker ~]# docker run -itd --name container2 -c 512 centos:7
1843a0bdc2a028b42d67451223d4c2ee8047c870ebdd3392a16609ff4e14315f
[root@docker ~]# cd /sys/fs/cgroup/cpu/docker/1843a0bdc2a028b42d67451223d4c2ee8047c870ebdd3392a16609ff4e14315f/
[root@docker 1843a0bdc2a028b42d67451223d4c2ee8047c870ebdd3392a16609ff4e14315f]# cat cpu.shares
512
[root@docker ~]# docker run -itd --name container3 centos:7
266d55197da604f83af60afa5ea33d51f3e97747afe64da69ad03c56ba342062
[root@docker ~]# cd /sys/fs/cgroup/cpu/docker/266d55197da604f83af60afa5ea33d51f3e97747afe64da69ad03c56ba342062/
[root@docker 266d55197da604f83af60afa5ea33d51f3e97747afe64da69ad03c56ba342062]# cat cpu.shares
1024

容器的Block IO
磁盘的读写
docker可以通过设置权重限制bps和iops的方式来控制容器读写磁盘的IO。

bps:每秒读写的数据量(byte per second);

iops:每秒IO的次数(io per second);

默认所有容器都能够平等的读写磁盘,但是可以通过–blkio-weight改变容器block IO的优先级。

--device-read-bps:显示读取某个设备的bps;

--device-write-bps:显示写入某个设备的bps;

--device-read-iops:显示读取某个设备的iops;

--device-write-iops:显示写入某个设备的iops;

示例:限制容器写入/dev/sda磁盘的bps为30MB。

[root@docker ~]# docker run -itd --name container4 --device-write-bps /dev/sda:30MB centos:7
a53e5e291efefc17c5817d9517f479265c4a66c60cf0ca0f488229567da5ddaa

从/dev/zero输入,然后输出到test.txt中,每次大小为100M,总共8次,oflag=direct用来指定direct IO方式写文件,这样才会使–device-write-bps生效。

[root@docker ~]# docker exec -it container4 bash
[root@a53e5e291efe /]# time dd if=/dev/zero of=test.txt bs=100M count=8 oflag=direct
8+0 records in
8+0 records out
838860800 bytes (839 MB) copied, 27.2297 s, 30.8 MB/s

real	0m27.234s
user	0m0.000s
sys	0m0.789s

再运行一个不做限制的容器对比。

[root@docker ~]# docker run -itd --name container5 centos:7
c6ce076d6a64bfd6ae540d63d225a35def68c99b7a61861b52b3c783f5ba5753
[root@docker ~]# docker exec -it container5 bash
[root@c6ce076d6a64 /]# time dd if=/dev/zero of=test.txt bs=100M count=8 oflag=direct
8+0 records in
8+0 records out
838860800 bytes (839 MB) copied, 0.606193 s, 1.4 GB/s

real	0m0.609s
user	0m0.001s
sys	0m0.606s

三、基本操作命令

查找镜像

[root@docker ~]# docker search busybox

拉取下载镜像

[root@docker ~]# docker pull busybox

查看本地镜像

[root@docker ~]# docker images

注意:一个完整的镜像,由镜像名称和TAG组成。如果只看到镜像的名称,没有接标签,意思是默认标签:latest。
虽然查看到的镜像标签为latest,但并不表示它一定是最新的。
把镜像导出到本地

[root@docker ~]# docker save -o busybox.tar busybox:latest

或者

[root@docker ~]# docker save > busybox.tar busybox:latest

删除镜像

[root@docker ~]# docker rmi busybox:latest

根据本地镜像包导入镜像

[root@docker ~]# docker load -i busybox.tar

或者

[root@docker ~]# docker load < busybox.tar

查看正在运行的容器

[root@docker ~]# docker ps

查看所有容器(运行的和没有运行的)

[root@docker ~]# docker ps -a

删除容器

[root@docker ~]# docker rm container1

注意:强制删除正在运行的容器可以加上-f选项。
创建容器

[root@docker ~]# docker create -it --name test centos:7

注意:创建完成后,容器状态为created。
启动容器

[root@docker ~]# docker start test

停止运行容器

[root@docker ~]# docker stop test

重启容器

[root@docker ~]# docker restart test

挂起容器

[root@docker ~]# docker pause test

挂起状态恢复正常

[root@docker ~]# docker unpause test

强制删除所有容器(生产环境禁止使用)

[root@docker ~]# docker ps -a -q | xargs docker rm -f

强制启动所有容器

[root@docker ~]# docker ps -a -q | xargs docker start

同理,还可以有强制停止、重启、挂起等操作。
运行容器

[root@docker ~]# docker run -itd --name test centos:7

参数解释

-i:可交互;

-t:伪终端;

-d:后台运行;

--name:给容器命名;

--restart=always:始终保持运行(随着docker开启而运行);

--rm:会随着退出容器的操作而删除容器;

进入容器

[root@docker ~]# docker exec -it test bash

或者

[root@docker ~]# docker attach test

区别

进入方式
exec:进入需要添加-i、-t选项,后面还要给容器一个shell环境;
attach:可以直接进入;

退出状态
exec:如果执行exit退出,容器仍然保持运行;
attach:如果执行exit退出,容器会被关闭。
如果想要保持容器不被关闭,可以使用键盘:Ctrl+p、Ctrl+q可以实现;

本质区别
exec:进入会生产新进程;
attach:进入不会生产新进程;

宿主机和容器之间相互传文件

[root@docker ~]# docker cp nginx-1.16.0.tar.gz test:/root

将容器制作成镜像

[root@docker ~]# docker commit test myweb

通过一个例子来展示docker的操作逻辑
基于centos:7镜像运行一个容器,并且在容器内部署nginx服务。
1.下载镜像

[root@docker ~]# docker pull centos:7

2.运行容器

[root@docker ~]# docker run -itd --name webapp --restart=always centos:7

3.进入容器部署nginx服务,将nginx包导入到容器内。

[root@docker ~]# docker cp nginx-1.6.0.tar.gz webapp:/root
[root@docker ~]# docker attach webapp
[root@badccc243dff /]# cd /root/
[root@badccc243dff ~]# tar -zxf nginx-1.6.0.tar.gz
[root@badccc243dff ~]# cd nginx-1.6.0
[root@badccc243dff nginx-1.6.0]# yum -y install gcc gcc-c++ pcre pcre-devel openssl opessl-devel zlib zlib-devel
[root@badccc243dff nginx-1.6.0]# useradd -M -s /sbin/nologin nginx
[root@badccc243dff nginx-1.6.0]# ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx 
[root@badccc243dff nginx-1.6.0]# make && make install
[root@badccc243dff nginx-1.6.0]# ln -s /usr/local/nginx/sbin/* /usr/local/sbin/
[root@badccc243dff nginx-1.6.0]# nginx
[root@badccc243dff nginx-1.6.0]# cd /usr/local/nginx/html/
[root@badccc243dff html]# vi index.html
<h1>welcome test-web on container</h1>
<div id="datetime">
    <script>
        setInterval("document.getElementById('datetime').innerHTML=new Date().toLocaleString();", 1000);
    </script>
</div>

4.将容器制作成镜像

[root@master ~]# docker commit webapp nginx:1
[root@docker ~]# docker run -itd --name web -p 80 nginx:1 nginx -g "daemon off;"
[root@master ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS              PORTS                   NAMES
3790c858081e        nginx:1             "nginx -g 'daemon of…"   About a minute ago   Up About a minute   0.0.0.0:32768->80/tcp   web

5.浏览器访问

192.168.229.187:32768

在这里插入图片描述
docker架构
在这里插入图片描述

四、Dockerfile相关介绍

docker的最小镜像

[root@docker ~]# docker pull hello-world

可以参考官网查看Dockerfile
在这里插入图片描述
Dockerfile组成

1.FROM scratch
2.COPY hello /
3.CMD ["/hello"]

base镜像
centos:7镜像的Dockerfile组成

FROM scratch
ADD centos-7-x86_64-docker.tar.xz /
LABEL \
      org.label-schema.schema-version="1.0" \
      org.label-schema.name="CentOS Base Image" \
      org.label-schema.vendor="CentOS" \
      org.label-schema.license="GPLv2" \
      org.label-schema.build-date="20200504" \
      org.opencontainers.image.title="CentOS Base Image" \
      org.opencontainers.image.vendor="CentOS" \
      org.opencontainers.image.licenses="GPL-2.0-only" \
      org.opencontainers.image.created="2020-05-04 00:00:00+01:00"
      CMD ["/bin/bash"]

镜像的分层

1.dockerfile的书写格式:Dockerfile;

2.FROM:构建镜像有两种方式,一种是scratch(从零构建),另一种可以基于某个镜像开始构建;

3.镜像所运行的操作(用户所期望的);

根据Dockerfile文件制作镜像

[root@docker test1]# vim Dockerfile
FROM centos:7
RUN yum -y install vim
RUN yum -y install net-tools
CMD {"/bin/bash"}
[root@docker test1]# docker build -t test:1 .

注意:最后那个点是寻找目录中的Dockerfile文件。如果Dokerfile文件不在当前目录,需要指定目录时,可以加上-f,后面加上路径,最后还有加个点。
在这里插入图片描述
Dockerfile镜像分层总结
镜像是容器的基石,容器是镜像运行后的实例。
当镜像运行为容器后,对镜像的所有数据仅有只读权限,如果需要对镜像源文件进行修改或删除,此时是在容器层(可写层)进行的,用到了COW(copy on write)写时复制机制。
Docker镜像缓存特性
创建一个新的Dockerfile文件

[root@docker test2]# vim Dockerfile
FROM centos:7
RUN yum -y install vim
RUN yum -y install net-tools
RUN yum -y install wget
CMD {"/bin/bash"}
[root@docker test2]# docker build -t test:2 .

1.如果在相同的层用到相同的镜像,可以不必再去下载,直接使用缓存。
创建一个新的Dockerfile

[root@docker test2]# vim Dockerfile
FROM centos:7
RUN yum -y install vim
RUN yum -y install wget
RUN yum -y install net-tools
CMD {"/bin/bash"}
[root@docker test2]# docker build -t test:3 .

2.即使镜像层里的操作一样,也必须是在同一层才可以使用dockerfile的缓存特性。
如果制作镜像过程中,不想使用缓存,可以加–no-cache选项。
3.如果前边的层发生改变,即使后边的层操作和顺序一样,也不能使用缓存特性。
Dockerfile常用指令

FROM:构建镜像基于哪个镜像
例如:
FROM centos:7

MAINTAINER:镜像维护者姓名或邮箱地址
例如:
MAINTAINER adam

RUN:构建镜像时运行的shell命令
例如:
RUN ["yum","install","httpd"]
RUN yum -y install httpd

CMD:运行容器时执行的shell命令
例如:
CMD ["/bin/bash"]

EXPOSE:声明容器的服务端口
例如:
EXPOSE 80 443

ENV:设置容器环境变量
例如:
ENV MYSQL_ROOT_PASSWORD 123.com

ADD:拷贝文件或目录到镜像,如果是URL或压缩包会自动下载或自动解压
例如:
ADD <源文件>... <目标目录>
ADD ["源文件"..."目标目录"]

COPY:拷贝文件或目录到镜像容器内,跟ADD类似,但不具备自动下载或解压功能

ENTRYPOINT:运行容器时执行的shell命令
例如:
ENTRYPOINT ["/bin/bash","-c","command"]
ENTRYPOINT /bin/bash -c 'command'

VOLUME:指定容器挂载点到宿主机自动生成的目录或其他容器
例如:
VOLUME ["/var/lib/mysql"]

USER:为RUN、CMD、和ENTRYPOINT执行命令指定运行用户

WORKDIR:为RUN、CMD、ENTRYPOINT、COPY和ADD设置工作目录,意思为切换目录
例如:
WORKDIR /var/lib/mysql

HEALTHCHECK:健康检查

ARG:构建时指定的一些参数
例如:
FROM centos:7
ARG user
USER $user

注意

(1)RUN在building时运行,可以写多条。其实RUN是有条件限制的()。

(2)CMD和ENTRYPOINT在运行container时运行,只能写一条,如果写多条,最后一条生效。

(3)CMD在run时可以被COMMAND覆盖,ENTRYPOINT不会被COMMAND覆盖,但可以指定--entrypoint覆盖。

(4)如果在Dockerfile里需要往镜像内导入文件,则此文件必须在dockerfile所在目录或子目录下。

(5)一个目录下,只能有一个Dockerfile文件,并且名称的大小写严格按照要求:Dockerfile。

通过实验来演示docker部署nginx服务
写一个dockerfile,基于centos:7镜像,部署安装NGINX服务。

FROM centos:7
RUN yum -y install gcc gcc-c++ pcre pcre-devel zlib zlib-devel openssl openssl-devel
COPY nginx-1.6.0.tar.gz /
RUN tar -zxf nginx-1.6.0.tar.gz
RUN useradd -M -s /sbin/nologin nginx
WORKDIR /nginx-1.6.0
RUN ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx
RUN make && make install
RUN ln -s /usr/local/nginx/sbin/* /usr/local/sbin/
RUN nginx
EXPOSE 80
[root@docker test2]# docker build -t webapp:1 .

注意:此工作目录和dockerfile是在同一个目录中。
如果想要保证容器运行之后,nginx服务就直接开启,不必手动开启,可以在命令最后加上:nginx -g "daemon off;"选项。

[root@docker test2]# docker run -itd --name testweb -p 80 webapp:1 nginx -g "daemon off;"
五、私有镜像仓库

Docker Hub
官网

https://hub.docker.com/

目前Docker官方维护了一个公共仓库Docker Hub,大部分需求都可以通过在Docker Hub中直接下载镜像来实现。如果觉得拉取Docker Hub的镜像比较慢,可以配置一个镜像加速器,当然国内大部分云厂商都提供了相应的加速器。
注册
可以在https://cloud.docker.com免费注册一个Docker账号。
登录
通过执行docker login命令交互式的输入用户名及密码来完成在命令行界面登录Docker Hub。
注销
可以通过docker logout退出登录。
Registry
有时使用Docker Hub这样的公共仓库可能不方便,用户可以创建一个本地仓库供私人使用。
docker-registry是官方提供的工具,可以用于构建私有的镜像仓库。可以通过获取官方registry镜像来运行。
一般情况下,不论是通过commit容器得到的镜像,或者是用dockerfile制作的镜像,如果需要将镜像保存,可以使用之前提到的导出导入命令(save -o;load -i)。导出的包,然后再传给其他dockerHost,这种方法也是可行的。
但往往在公司会有大量的镜像,而且不仅仅是单台的dockerHost。需要有一个本地共用的仓库,来实现多台dockerHost直接拉取镜像而不用手动的将镜像传来传去,之前的DockerHub可以解决这个问题,当然需要申请一个DockerHub账号,创建一个仓库。但这种方法需要消耗带宽,因为是通过网络传输,既然是网络传输,就需要消耗一定的时间。
而Registry仓库,是通过一个容器来提供服务,是比较简易的私有仓库,以后在企业中还会有功能更加完善的Harbor仓库。
1.创建私有仓库
registry是官方提供的工具,可以用于构建私有的镜像仓库。
(1)docker容器运行registry私有仓库服务
下载需要的镜像

[root@docker ~]# docker pull registry:2

注意:这里使用的是registry:2版本,还有一个registry镜像,这两个没有太大的区别。registry是用Python语言写的,registry:2使用Go语言写的。理论上来说,registry:2这个版本运行更快些。
(2)运行私有仓库服务

[root@docker ~]# docker run -itd --name registry --restart=always -p 5000:5000 -v /registry:/var/lib/registry registry:2
81019d59210d2b95361945a9854ccf32ddc4f50ca3ff83692fb80b56058dfe27

参数介绍

-p:端口映射,宿主机端口:容器暴露的端口;

-p 80:如果-p选项后只写了一个端口,是指容器暴露的端口号随机映射到宿主机(32768开始...);

-P:后边没有接任何的端口参数。它会把容器暴露的端口,全部随机的映射到宿主机;

-v:挂载目录。宿主机的目录:容器内的目录;

(3)镜像重命名
因为使用的是私有镜像,在上传或下载时都需要将镜像的名称直接重命名,要注明它私有仓库的IP地址:暴露端口。切记是必须,否则将识别不到仓库而上传或下载失败。

格式:
docker tag IMAGE[:TAG] [REGISTRY_HOST[:REGISTRY_PORT]/]REPOSITORY[:TAG]
[root@docker ~]# docker tag registry:2 192.168.229.187:5000/registry:v1

(4)编辑docker配置文件
因为docker默认是从dockehub上下载镜像的,需要在本地指定一下私有仓库的IP加端口,这是因为Docker默认不允许非HTTPS方式推送镜像。如果没做这一步,会报HTTPS的错。
编辑docker的配置文件,指定私有仓库地址。

[root@docker ~]# vim /usr/lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd --insecure-registry 192.168.229.187:5000
[root@docker ~]# systemctl daemon-reload
[root@docker ~]# systemctl restart docker.service

(5)上传到私有仓库

[root@docker ~]# docker push 192.168.229.187:5000/registry:v1

注意:既然是私有仓库,肯定是要考虑多台DockerHost共用的情况,如果有其他的DockerHost想要使用私有仓库,仅需要修改docker的配置文件,指定私有仓库的IP和端口即可。
查看有哪些镜像

[root@docker ~]# curl -XGET http://192.168.229.187:5000/v1/_catalog
-X/--request:指定什么命令
-G/--get:以get的方式来发送数据
-E/--cert cert[:passwd]:客户端证书文件和密码(SSL)
-T/--upload-file:上传文件
[root@docker ~]# curl http://192.168.229.187:5000/v1/busybox/tags/list {"name":"mycentos","tags":["latest"]}  #并看不到详细的自定义 版本号

Harbor
Harbor是构建企业级私有docker镜像仓库的开源解决方案,它是Docker Registry的更高级封装,它除了提供友好的Web UI界面、角色和用户权限管理、用户操作审计等功能外,还整合了K8s的插件(Add-ons)仓库,即Helm通过chart方式下载、管理、安装K8s插件,而chartmuseum可以提供存储chart数据的仓库【helm相当于k8s的yum】。
另外还整合了两个开源的安全组件,一个是Notary,另一个是Clair,Notary类似私有CA中心,而Clair则是容器安全扫描工具,它通过各大厂商提供的CVE漏洞库来获取最新漏洞信息,并扫描用户上传的容器是否存在已知的漏洞信息,这两个安全功能对于企业级私有仓库来说是非常具有意义的。
Harbor安装有3种方式

在线安装:从Docker Hub下载Harbor相关镜像,因此安装软件包非常小;

离线安装:安装包包含部署的相关镜像,因此安装包比较大;

OVA安装程序:当用户具有vCenter环境时,使用此安装程序,在部署OVA后启动Harbor;

这里选用离线安装的方式。
1.下载docker-compse工具
从github上下载

[root@docker ~]# curl -L https://github.com/docker/compose/releases/download/1.25.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose

也可以提前准备好tar包直接解压
[root@docker ~]# ls
anaconda-ks.cfg  docker-compose.1.25.0.tar.gz
[root@docker ~]# tar -zxf docker-compose.1.25.0.tar.gz
[root@docker ~]# cd usr/local/bin/
[root@docker bin]# ls
docker-compose
[root@docker bin]# mv docker-compose /usr/local/bin/
[root@docker bin]# chmod +x /usr/local/bin/docker-compose
[root@docker bin]# docker-compose -version
docker-compose version 1.25.0, build 0a186604

下载依赖包

[root@docker ~]# yum -y install yum-utils device-mapper-persistent-data lvm2

2.harbor离线模式
考虑到网速原因,采用离线下载方式。

[root@docker ~]# wget https://storage.googleapis.com/harbor-releases/release-1.7.0/harbor-offline-installer-v1.7.4.tgz

导入Harbor离线安装包,并解压到/usr/local/下

[root@docker ~]# tar -zxf harbor-offline-installer-v1.7.4.tgz -C /usr/local/

修改配置文件,指定harbor主机

[root@docker ~]# cd /usr/local/harbor
[root@docker harbor]# ls
common                          docker-compose.yml    LICENSE
docker-compose.chartmuseum.yml  harbor.cfg            open_source_license
docker-compose.clair.yml        harbor.v1.7.4.tar.gz  prepare
docker-compose.notary.yml       install.sh
[root@docker harbor]# vim harbor.cfg
hostname = 192.168.229.187

将主机名直接改成harbor主机的IP地址,其实也可以使用域名,如果使用域名需要在windows主机上修改hosts文件,地址为C:\Windows\System32\drivers\etc,将域名与ip添加进去。
配置文件介绍

## Configuration file of Harbor

hostname = 192.168.1.100  #hostname设置访问地址,可以使用ip、域名,不可以设置为127.0.0.1或localhost

ui_url_protocol = http  #访问协议,默认是http,也可以设置https,如果设置https,则nginx ssl需要设置on

max_job_workers = 10  #最大连接数

customize_crt = on  #是否生成证书
ssl_cert = /data/cert/server.crt
ssl_cert_key = /data/cert/server.key
secretkey_path = /data
admiral_url = NA

log_rotate_count = 50  #关于日志切割选项

log_rotate_size = 200M  #关于日志切割的大小,可以是KB、MB、GB

#是否启用代理访问
http_proxy =
https_proxy =
no_proxy = 127.0.0.1,localhost,core,registry

#邮件设置,发送重置密码邮件时使用
email_identity =
email_server = smtp.mydomain.com
email_server_port = 25
email_username = sample_admin@mydomain.com
email_password = abc
email_from = admin <sample_admin@mydomain.com>
email_ssl = false
email_insecure = false

#启动Harbor后,管理员admin,UI登录的密码默认是Harbor12345
harbor_admin_password = Harbor12345

#认证方式,这里支持多种认证方式,如LADP、本次存储、数据库认证。默认是db_auth,mysql数据库认证。
auth_mode = db_auth

#是否开启自注册
self_registration = on

#token有效时间,默认30分钟
token_expiration = 30

#用户创建项目权限控制,默认是everyone(所有人),也可以设置为adminonly(只能管理员)
project_creation_restriction = everyone

修改完配置文件后,在当前目录执行./install.sh,Harbor服务就会根据当期目录下的docker-compose.yml开始下载依赖的镜像,检测并按照顺序依次启动,注意harbor默认使用的是80端口,最好确认是否有冲突,或者也可以在docker-compose.yml中修改对应的端口。

[root@docker harbor]# ./install.sh

docker-compose命令可以管理harbor服务,不过需要注意的是想使用以下命令,必须是和docker-compose.yml这个文件在同一个目录下,其实就是通过管理这个文件而管理harbor仓库。

启动harbor
docker-compose start

停止harbor
docker-compose stop

重启harbor
docker-compose restart

harbor的使用

[root@docker harbor]# docker-compose start
Starting log         ... done
Starting registry    ... done
Starting registryctl ... done
Starting postgresql  ... done
Starting adminserver ... done
Starting core        ... done
Starting portal      ... done
Starting redis       ... done
Starting jobservice  ... done
Starting proxy       ... done

参数介绍

Proxy:是一个nginx的前端代理,代理Harbor的registry、UI、token等服务;

db:负责储存用户权限、审计日志、Dockerimage分组信息等数据;

UI:提供图形化界面,帮助用户管理registry上的镜像,并对用户进行授权;

jobservice:负责镜像复制工作,它和registry通信,从一个registry pull镜像然后push到另一个registry,并记录job_log;

Adminserver:是系统的配置管理中心附带检查存储用量,ui和jobserver启动时会需要加载adminserver的配置;

Registry:镜像仓库,负责存储镜像文件;

Log:为了帮助监控Harbor运行,负责收集其他组件的log,供日后进行分析;

通过浏览器访问harbor。

192.168.229.187

在这里插入图片描述
创建私有仓库
在这里插入图片描述
在这里插入图片描述
docker client的设置
1.更改docker配置文件
同理因为docker不支持https的原因,需要将docker的配置文件进行更改。

[root@docker ~]# vim /usr/lib/systemd/system/docker.service ExecStart=/usr/bin/dockerd --insecure-registry 192.168.229.187
[root@docker ~]# systemctl daemon-reload
[root@docker ~]# systemctl restart docker

2.客户端登录

[root@docker ~]# docker login -u admin -p Harbor12345 192.168.229.187

3.上传私有镜像

[root@docker ~]# docker tag nginx:latest 192.168.229.187/snow/nginx:v1
[root@docker ~]# docker push 192.168.229.187/snow/nginx:v1

在浏览器中可以看到相应的镜像
在这里插入图片描述

六、docker网络模式

dockerhost单主机网络方案
Docker网络从覆盖范围可分为单个host上的容器网络和跨多个host的网络,先看下面单个host上的网络。
查看docker的原生网络

[root@docker ~]# docker network ls
NETWORK ID       NAME     DRIVER     SCOPE
12ba7cfd57df     bridge   bridge     local
790e7df64d9d     host     host       local
04f6a0bc4f7f     none     null       local

1.none网络
就是什么都没有的网络。挂在这个网络下的容器除了lo,没有其他任何网卡。
容器创建时,可以通过–network=none指定使用none网络。

[root@docker ~]# docker run -itd --name none --network none busybox
[root@docker ~]# docker exec -it none sh
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
      link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
      inet 127.0.0.1/8 scope host lo
          valid_lft forever preferred_lft forever

注意:用到none网络的容器,只有一个Loopback回环的网络,没有Mac地址、IP等信息,意味着它不能跟外界通信,是被隔离起来的网络。
使用场景:这样一个封闭的网络有什么用?
封闭意味着隔离,一些对安全性要求高并且不需要联网的应用可以使用none网络。
比如某个容器的唯一用途是生成随机密码,就可以放到none网络中避免密码被窃取。
2.host网络
如果启动容器时使用host模式,那么这个容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个Network Namespace。
容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。但是容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。
连接到host网络的容器共享Docker host的网络栈,容器的网络配置与host完全一样。
可以通过–network=host指定使用host网络。

[root@docker ~]# docker run -itd --name host --network host busybox
[root@docker ~]# docker exec -it host sh
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
        valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
        valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast qlen 1000
    link/ether 00:0c:29:8b:84:97 brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.100/24 brd 192.168.1.255 scope global ens33
        valid_lft forever preferred_lft forever
    inet6 fe80::8099:248f:d536:5872/64 scope link
        valid_lft forever preferred_lft forever

注意:用到Host网络的容器,它的网络跟宿主机的网络一模一样,那是因为在创建这个容器时,并没有对它的Net网络栈进行隔离,而是直接使用的宿主机的网络栈。
使用场景:直接使用Docker host的网络最大的好处就是性能,如果容器对网络传输效率有较高要求,则可以选择host网络。当然不便之处就是牺牲一些灵活性,比如要考虑端口冲突问题,Docker host上已经使用的端口就不能再用了。
3.bridge桥接网络
当Docker进程启动时,会在主机上创建一个名为docker0的虚拟网桥,此主机上启动的Docker容器会连接到这个虚拟网桥上。
虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。从docker0子网中分配一个IP给容器使用,并设置docker0的IP地址为容器的默认网关。在主机上创建一对虚拟网卡veth pair设备,Docker将veth pair设备的一端放在新创建的容器中,并命名为eth0(容器的网卡),另一端放在主机中,以vethxxx这样类似的名字命名,并将这个网络设备加入到docker0网桥中。可以通过brctl show命令查看。
bridge模式是docker的默认网络模式,不写network参数,就是bridge模式。使用docker run -p时,docker实际是在iptables做了DNAT规则,实现端口转发功能。
可以使用iptables -t nat -vnL查看。

[root@docker ~]# brctl show

docker0:在安装docker服务时,默认就会生产一张docker0的网卡,一般默认IP为172.17.0.1/16。

[root@docker ~]# docker run -itd --name test busybox
[root@docker ~]# docker exec -it test sh

容器默认使用的网络是docker0网络,docker0此时相当于一个路由器,基于此网络的容器,网段都是和docker0一致的。
4.自定义网络(bridge)
自带了一个Container DNSserver功能(域名解析)
基于bridge
创建一个bridge网络

[root@docker ~]# docker network create -d bridge my_net
[root@docker ~]# docker network ls
NETWORK ID     NAME     DRIVER     SCOPE
573f825b93e8   bridge   bridge     local
790e7df64d9d   host     host       local
edbb85ec19bc   my_net1  bridge     local
04f6a0bc4f7f   none     null       local
[root@docker ~]# brctl show
bridge name     bridge id      STP enabled   interfaces
br-edbb85ec19bc 8000.0242f46b8c67   no
docker0         8000.02428cafa127   no       veth311e633
                                             vethaf71ece
[root@docker ~]# docker run -itd --name test1 --network my_net busybox
[root@docker ~]# docker run -itd --name test2 --network my_net busybox

注意:自定义网络的优点,它可以通过容器的名称通信。

[root@docker ~]# docker exec -it test1 sh
/ # ping test2
PING test2 (172.18.0.3): 56 data bytes
64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.060 ms
64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.088 ms
...

创建一个自定义网络,并且指定网关和网段。

[root@docker ~]#  docker network create -d bridge --subnet 172.20.16.0/24 --gateway 172.20.16.1 my_net1
[root@docker ~]# docker run -itd --name test3 --network my_net1 --ip 172.20.16.6 busybox
[root@docker ~]# docker run -itd --name test4 --network my_net1 --ip 172.20.16.8 busybox

注意:如果想要给容器指定IP地址,那么自定义网络时,必须指定网关gateway和subnet网段。
在这里插入图片描述
注意:test2能ping通my_net1网关,但ping不通test3和test4;同理,test4能ping通my_net2,但ping不通test5和test6。
这是因为iptabeles防火墙规则导致的,但不允许为了实现这个功能对防火墙进行操作,因为涉及安全,须谨慎,所以采用另外的方法。
解决思路:在test2容器内新添加一块网卡,并且让它获取my_net1的网段。

[root@docker ~]# docker network connect my_net1 test2

5.join容器:container(共享网络协议栈)
容器和容器之间。
这个模式指定新创建的容器和已经存在的一个容器共享一个Network Namespace,而不是和宿主机共享。
新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过lo网卡设备通信。

[root@docker ~]# docker run -itd --name web1 busybox
[root@docker ~]# docker run -itd --name web2 --network container:web1 busybox
[root@docker ~]# docker exec -it web1 sh
/ # echo 123456 > /tmp/index.html
/ # httpd -h /tmp/
[root@docker ~]# docker exec -it web2 sh
/ # wget -O - -q 127.0.0.1
123456

这时会发现两个容器的IP地址一样。
这种方法的使用场景:由于这种网络的特殊性,一般在运行同一个服务,并且这个服务需要做监控,以及日志收集、或者网络监控时,可以选择这种网络。
6.让外网能够访问容器
端口映射方法

(1)手动指定端口映射关系
[root@docker ~]# docker run -itd --name web3 -p 90:80 nginx

(2)从宿主机随机映射端口到容器
[root@docker ~]# docker run -itd --name web4 -p 80 nginx

(3)从宿主机随机映射端口到容器,容器内所有暴露端口,都会一一映射
[root@docker ~]# docker run -itd --name web5 -P nginx

每一个映射的端口,host都会启动一个docker-proxy进程来处理访问容器的流量。

[root@docker ~]# ps -ef | grep docker-proxy

7.docker的跨主机网络
方案一:overlay
为支持容器跨主机通信,Docker提供了overlay driver,使用户可以创建基于VxLAN的overlay网络。
VxLAN可将二层数据封装到UDP进行传输,VxLAN提供与VLAN相同的以太网二层服务,但是拥有更强的扩展性和灵活性。
在这里插入图片描述
overlay网络需要一个key-value数据库用于保存网络状态信息,包括Network、Endpoint、IP等。
Consul、Etcd和ZooKeeper都是Docker支持的key-vlaue软件,这里使用Consul。
环境限制

(1)必须安装key-value存储服务,如consul;

(2)宿主机已经安装docker engine;

(3)宿主机的hostname必须不同;

实验环境

docker1:192.168.229.187
docker2:192.168.229.40
docker3:192.168.229.50

暂时不考虑防火墙和selinux安全问题,将3台dockerhost防火墙和selinux全部关闭并分别更改主机名称。

[root@docker1 ~]# systemctl stop firewalld
[root@docker1 ~]# systemctl disable firewalld
[root@docker1 ~]# setenforce 0

在docker1上操作
运行consul服务

[root@docker1 ~]# docker run -d -p 8500:8500 -h consul --name consul --restart always progrium/consul -server -bootstrap

注意:容器生产之后,可以通过浏览器访问consul服务,验证consul服务是否正常。
访问dockerhost加映射端口。

192.168.229.187:8500

修改docker配置文件(三台主机)

[root@docker1 ~]# vim /usr/lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H unix:///var/run/docker.sock -H tcp://0.0.0.0:2376 --cluster-store=consul://192.168.229.187:8500 --cluster-advertise=ens33:2376
[root@docker1 ~]# systemctl daemon-reload
[root@docker1 ~]# systemctl restart docker

注意:返回浏览器consul服务界面,找到KEY/VALUE---->DOCKER---->NODES,会看到刚刚加入的docker2和docker3的信息。
在docker1上创建一个自定义网络

[root@docker1 ~]# docker network create -d overlay ov_net1
[root@docker1 ~]# docker network ls
NETWORK ID    NAME   DRIVER  SCOPE
5ec0c207991c ov_net1 overlay global

在docker1上创建的网络,可以看到它的SCOPE定义的是global,意味着加入到consul这个服务的docker服务,都可以看到自定义的网络。

[root@docker2 ~]# docker network ls
NETWORK ID    NAME   DRIVER  SCOPE
5ec0c207991c ov_net1 overlay global
[root@docker3 ~]# docker network ls
NETWORK ID    NAME   DRIVER  SCOPE
5ec0c207991c ov_net1 overlay global

同理如果是用此网络创建的容器,会有两张网卡。默认这张网卡的网段是10.0.0.0网段,如果想要docker1也能看到这个网络,那么也只需在docker1的docker配置文件添加相应内容即可。

[root@docker1 ~]# docker run -itd --name ov1 --network ov_net1 busybox
[root@docker2 ~]# docker run -itd --name ov2 --network ov_net1 busybox
[root@docker1 ~]# docker exec -it ov1 sh
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
10: eth0@if11: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1450 qdisc noqueue
    link/ether 02:42:0a:00:00:02 brd ff:ff:ff:ff:ff:ff
    inet 10.0.0.2/24 brd 10.0.0.255 scope global eth0
       valid_lft forever preferred_lft forever
13: eth1@if14: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
    link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.2/16 brd 172.18.255.255 scope global eth1
       valid_lft forever preferred_lft forever
/ # ping 10.0.0.3
PING 10.0.0.3 (10.0.0.3): 56 data bytes
64 bytes from 10.0.0.3: seq=0 ttl=64 time=0.771 ms
64 bytes from 10.0.0.3: seq=1 ttl=64 time=0.723 ms
^C
--- 10.0.0.3 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.723/0.747/0.771 ms
/ # ping ov2
PING ov2 (10.0.0.3): 56 data bytes
64 bytes from 10.0.0.3: seq=0 ttl=64 time=0.502 ms
64 bytes from 10.0.0.3: seq=1 ttl=64 time=0.648 ms
^C
--- ov2 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.502/0.575/0.648 ms

同理,因为是自定义网络,符合自定义网络的特性,可以直接通过docker容器的名称相互通信,当然也可以在自定义网络时,指定它的网段,那么使用此网络的容器也可以指定IP地址。

[root@docker ~]# docker network create -d overlay --subnet 10.10.10.0/24 --gateway 10.10.10.1 ov_net2
[root@docker ~]# docker run -itd --name ov3 --network ov_net2 --ip 10.10.10.10 busybox
[root@docker2 ~]# docker run -itd --name ov4 --network ov_net2 --ip 10.10.10.11 busybox
[root@docker ~]# docker exec -it ov3 sh
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
16: eth0@if17: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1450 qdisc noqueue
    link/ether 02:42:0a:0a:0a:0a brd ff:ff:ff:ff:ff:ff
    inet 10.10.10.10/24 brd 10.10.10.255 scope global eth0
       valid_lft forever preferred_lft forever
18: eth1@if19: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
    link/ether 02:42:ac:12:00:03 brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.3/16 brd 172.18.255.255 scope global eth1
       valid_lft forever preferred_lft forever
/ # ping 10.10.10.10
PING 10.10.10.10 (10.10.10.10): 56 data bytes
64 bytes from 10.10.10.10: seq=0 ttl=64 time=0.057 ms
64 bytes from 10.10.10.10: seq=1 ttl=64 time=0.070 ms
64 bytes from 10.10.10.10: seq=2 ttl=64 time=0.085 ms
^C
--- 10.10.10.10 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.057/0.070/0.085 ms
/ # ping ov4
PING ov4 (10.10.10.11): 56 data bytes
64 bytes from 10.10.10.11: seq=0 ttl=64 time=0.450 ms
64 bytes from 10.10.10.11: seq=1 ttl=64 time=0.583 ms
64 bytes from 10.10.10.11: seq=2 ttl=64 time=0.657 ms
64 bytes from 10.10.10.11: seq=3 ttl=64 time=0.793 ms
^C
--- ov4 ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 0.450/0.620/0.793 ms

在这里插入图片描述
方案二:MacVlan
除了overlay,docker还开发了另一个支持跨主机容器网络的driver:macvlan。
macvlan本身是Linux kernel模块,其功能是允许在同一个物理网卡上配置多个MAC地址,即多个interface,每个interface可以配置自己的IP。
macvlan本质上是一种网卡虚拟化技术,Docker用macvlan实现容器网络就不奇怪了。
macvlan的最大优点是性能极好,相比其他实现,macvlan不需要创建Linux bridge,而是直接通过以太interface连接到物理网络。
下面我们就来创建一个macvlan网络。
实验环境

docker1:192.168.229.187
docker2:192.168.229.40

关闭防火墙与selinux并更改主机名。
1.macvlan的单网络通信
在这里插入图片描述
(1)打开网卡的混杂模式(两台主机)

[root@docker ~]# ip link set ens33 promisc on
[root@docker ~]# ip link show ens33
2: ens33: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether 00:0c:29:07:f1:dd brd ff:ff:ff:ff:ff:ff

(2)在docker1上创建macvlan网络

[root@docker ~]# docker network create -d macvlan --subnet 172.22.16.0/24 --gateway 172.22.16.1 -o parent=ens33 mac_net1

注意:-o parent=绑定在哪张网卡之上
(3)基于创建的macvlan网络运行一个容器

[root@docker ~]# docker run -itd --name mv1 --ip 172.22.16.10 --network mac_net1 busybox
[root@docker ~]# docker exec -it mv1 sh
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
20: eth0@if2: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
    link/ether 02:42:ac:16:10:0a brd ff:ff:ff:ff:ff:ff
    inet 172.22.16.10/24 brd 172.22.16.255 scope global eth0
       valid_lft forever preferred_lft forever

(4)在docker2上创建macvlan网络,注意与docker1上的macvlan网络相同

[root@docker2 ~]# docker network create -d macvlan --subnet 172.22.16.0/24 --gateway 172.22.16.1 -o parent=ens33 mac_net1

(5)在docker2上,基于创建的macvlan网络运行一个容器,验证与docker1上容器的通信

[root@docker2 ~]# docker run -itd --name mv2 --network mac_net1 --ip 172.22.16.11 busybox
[root@docker2 ~]# docker exec -it mv2 sh
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
16: eth0@if2: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
    link/ether 02:42:ac:16:10:0b brd ff:ff:ff:ff:ff:ff
    inet 172.22.16.11/24 brd 172.22.16.255 scope global eth0
       valid_lft forever preferred_lft forever
/ # ping 172.22.16.10
PING 172.22.16.10 (172.22.16.10): 56 data bytes
64 bytes from 172.22.16.10: seq=0 ttl=64 time=0.911 ms
64 bytes from 172.22.16.10: seq=1 ttl=64 time=0.491 ms
^C
--- 172.22.16.10 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.491/0.701/0.911 ms

可以ping通IP地址,但是不能通过域名进行通信。
2.macvlan的多网络通信
在这里插入图片描述
(1)docker1和docker2验证内核模块8021q封装

macvlan需要解决的问题:基于真实的ens33网卡生产新的虚拟网卡。
[root@docker ~]# modinfo 8021q

如果内核模块没有开启,运行下边的命令导入一下。
[root@docker ~]# modprobe 8021q

(2)基于ens33创建虚拟网卡
修改ens33网卡配置文件

[root@docker ~]# cd /etc/sysconfig/network-scripts/
[root@docker network-scripts]# vim ifcfg-ens33
把BOOTPROTO=改为手动模式BOOTPROTO="manual"
这里manual等价于static等价于none。

手动添加虚拟网卡配置文件

[root@docker network-scripts]# cp ifcfg-ens33 ifcfg-ens33.10
[root@docker network-scripts]# vim ifcfg-ens33.10
BOOTPROTO="static"
DEFROUTE="yes"
NAME="ens33.10"
DEVICE="ens33.10"
ONBOOT="yes"
IPADDR=192.168.10.10
GATEWAY=192.168.10.2
PREFIX=24
VLAN=yes

注意:IP要和ens33网段做一个区分,保证网关和网段IP的一致性,设备名称和配置文件的一致性,并且打开VLAN支持模式。
创建第二个虚拟网卡配置文件

[root@docker network-scripts]# cp ifcfg-ens33.10 ifcfg-ens33.20
[root@docker network-scripts]# vim ifcfg-ens33.20
BOOTPROTO="static"
DEFROUTE="yes"
NAME="ens33.20"
DEVICE="ens33.20"
ONBOOT="yes"
IPADDR=192.168.20.20
GATEWAY=192.168.20.2
PREFIX=24
VLAN=yes

(3)docker1上启用创建的虚拟网卡

[root@docker network-scripts]# ifup ifcfg-ens33.10
[root@docker network-scripts]# ifup ifcfg-ens33.20
[root@docker network-scripts]# ip a
...
21: ens33.10@ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 00:0c:29:07:f1:dd brd ff:ff:ff:ff:ff:ff
    inet 192.168.10.10/24 brd 192.168.10.255 scope global noprefixroute ens33.10
       valid_lft forever preferred_lft forever
    inet6 fe80::20c:29ff:fe07:f1dd/64 scope link
       valid_lft forever preferred_lft forever
22: ens33.20@ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 00:0c:29:07:f1:dd brd ff:ff:ff:ff:ff:ff
    inet 192.168.20.20/24 brd 192.168.20.255 scope global noprefixroute ens33.20
       valid_lft forever preferred_lft forever
    inet6 fe80::20c:29ff:fe07:f1dd/64 scope link
       valid_lft forever preferred_lft forever

(4)基于虚拟网卡,创建macvlan网络

[root@docker network-scripts]# docker network create -d macvlan --subnet 172.16.10.0/24 --gateway 172.16.10.1 -o parent=ens33.10 mac_net10
[root@docker network-scripts]# docker network create -d macvlan --subnet 172.16.20.0/24 --gateway 172.16.20.1 -o parent=ens33.20 mac_net20

(5)基于上述创建的macvlan网络,运行对应的容器,不过这里需要注意,运行的容器与网络对应的网段相符合,还有IP地址的唯一性。

[root@docker network-scripts]# docker run -itd --name mv10 --network mac_net10 --ip 172.16.10.10 busybox
[root@docker network-scripts]# docker run -itd --name mv20 --network mac_net20 --ip 172.16.20.20 busybox

(6)在docker2上创建网络及容器
注意:操作跟在docker1上的操作相同。

[root@docker2 ~]# modinfo 8021q
[root@docker ~]# cd /etc/sysconfig/network-scripts/
[root@docker network-scripts]# vim ifcfg-ens33
把BOOTPROTO=改为手动模式BOOTPROTO="manual"
这里manual等价于static等价于none。
[root@docker network-scripts]# cp ifcfg-ens33 ifcfg-ens33.10
[root@docker network-scripts]# vim ifcfg-ens33.10
BOOTPROTO="static"
DEFROUTE="yes"
NAME="ens33.10"
DEVICE="ens33.10"
ONBOOT="yes"
IPADDR=192.168.10.11
GATEWAY=192.168.10.2
PREFIX=24
VLAN=yes
[root@docker network-scripts]# cp ifcfg-ens33.10 ifcfg-ens33.20
[root@docker network-scripts]# vim ifcfg-ens33.20
BOOTPROTO="static"
DEFROUTE="yes"
NAME="ens33.20"
DEVICE="ens33.20"
ONBOOT="yes"
IPADDR=192.168.20.21
GATEWAY=192.168.20.2
PREFIX=24
VLAN=yes
[root@docker network-scripts]# ifup ifcfg-ens33.10
[root@docker network-scripts]# ifup ifcfg-ens33.20
[root@docker network-scripts]# ip a
...
17: ens33.10@ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 00:0c:29:d2:91:56 brd ff:ff:ff:ff:ff:ff
    inet 192.168.10.11/24 brd 192.168.10.255 scope global noprefixroute ens33.10
       valid_lft forever preferred_lft forever
    inet6 fe80::20c:29ff:fed2:9156/64 scope link
       valid_lft forever preferred_lft forever
18: ens33.20@ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 00:0c:29:d2:91:56 brd ff:ff:ff:ff:ff:ff
    inet 192.168.20.21/24 brd 192.168.20.255 scope global noprefixroute ens33.20
       valid_lft forever preferred_lft forever
    inet6 fe80::20c:29ff:fed2:9156/64 scope link
       valid_lft forever preferred_lft forever
[root@docker network-scripts]# docker network create -d macvlan --subnet 172.16.10.0/24 --gateway 172.16.10.1 -o parent=ens33.10 mac_net10
[root@docker network-scripts]# docker network create -d macvlan --subnet 172.16.20.0/24 --gateway 172.16.20.1 -o parent=ens33.20 mac_net20
[root@docker network-scripts]# docker run -itd --name mv10 --network mac_net10 --ip 172.16.10.11 busybox
[root@docker network-scripts]# docker run -itd --name mv20 --network mac_net20 --ip 172.16.20.21 busybox
[root@docker2 network-scripts]# docker exec -it mv10 sh
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
19: eth0@if17: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
    link/ether 02:42:ac:10:0a:0b brd ff:ff:ff:ff:ff:ff
    inet 172.16.10.11/24 brd 172.16.10.255 scope global eth0
       valid_lft forever preferred_lft forever
/ # ping 172.16.10.10
PING 172.16.10.10 (172.16.10.10): 56 data bytes
64 bytes from 172.16.10.10: seq=0 ttl=64 time=0.895 ms
64 bytes from 172.16.10.10: seq=1 ttl=64 time=0.625 ms
64 bytes from 172.16.10.10: seq=2 ttl=64 time=0.616 ms
^C
--- 172.16.10.10 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.616/0.712/0.895 ms

结论:跨主机可以通过IP地址通信,但不能通过主机名通信。
如果步骤没有问题,可是还是ping不通,请把VMware的网络设置为Bridge模式再进行尝试。

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐