Docker基础

容器生命周期:

 

1、什么是容器
  a)一种虚拟化的方案
  b)操作系统级别的虚拟化
  c)只能运行相同或相似内核的操作系统
  d)依赖于Linux内核特性:Namespace和Cgroups(Control Group)
  e)docker是有go语言开发的
2、Docker的目标:
  a)提供简单轻量的建模方式
  b)职责的逻辑分离
  c)快速高效的开发生命周期
  d)鼓励使用面向服务的架构
3、Docker的使用场景
  a)使用docker容器开发,测试,部署服务
  b)创建隔离的运行环境
  c)搭建测试环境
  d)构建多用户的平台服务(PaaS)基础设施
  e)提供软件即服务(SaaS)应用程序
  f)高性能、超大规模的宿主机部署
4、Docker Image镜像
  a)容器的基石
  b)层叠的只读文件系统
  c)联合加载(union mount)
5、Docker Contrainer容器
  a)通过镜像启动
  b)启动和执行阶段
  c)写时复制
6、Docker Registry仓库
  a)公有,私有
  b)Docker Hub
7、Namespaces命名空间
  a)PID(Process ID) 进程隔离
  b)NET(Network) 管理网络接口
  c)IPC 管理跨进程通信的访问
  d)MNT 管理挂载点
  e)UTS 隔离内核和版本标识
8、Control groups控制组
  a)资源限制
  b)优先级设置
  c)资源计量
  d)资源控制
9、Docker 容器的能力
  a)文件系统隔离:每个容器都有自己的root文件系统
  b)进程隔离:每个容器都运行在自己的进程环境中
  c)网络隔离:容器间的虚拟网络接口和IP地址都是分开的
  d)资源隔离和分组:使用cgroups将CPU和内存之类的资源独立分配给每个Docker
10、容器的基本操作
10.1、启动容器:
  1、docker run IMAGE [COMMAND] [ARG...]
      run 在新容器中执行
  2、启动交互式容器
    docker run -i -t IMAGE /bin/bash
    -i --interactive=true|false 默认是false # 为容器始终打开标准输入
    -t --tty=true|false 默认是false # 为容器分配伪tty终端
10.2、查看容器:
  查看启动的容器:docker ps [-l]
  查看所有的容器:docker ps -a
  查看容器详细信息:docker inspect 容器名称/容器ID
10.3、自定义容器名;
  docker run --name=自定义名 -i -t IMAGE /bin/bash
10.4、重新启动停止的容器:
  docker start [-i] 容器名称/容器ID
10.5、删除停止的容器
  docker rm 容器名/ID # 只能删除暂停中的容器
11、守护式容器
  a)docker run -i -t IMAGE /bin/bash
    Ctrl+p Ctrl+Q 操作
  b)附加到运行中的容器
    docker attach 容器名
  c)启动守护式容器
    docker run -d 镜像名 [COMMAND] [ARG...]
  d)查看容器日志
    docker logs [-f][-t][--tail] 容器名 # 不指定参数返回所有的日志
    -f --follows=true|false 默认为false # 一直跟踪日志的变化,并返回结果
    -t --timestamps=true|false默认为false # 在返回的结果上加上时间戳
    --tail="all" # 返回结尾数多少数量的日志
  e)在运行中的容器内启动新进场
    docker top 容器名
  f)docker exec [-d][-i][-t] 容器名 [COMMAND] [ARG...]
  h)停止守护式容器
    docker stop 容器名 # 发送信号,等待停止
    docker kill 容器名 # 直接停止
12、在容器中部署静态网站
  a)设置容器的端口映射
    -p, --pushlish=[] # 指定端口
    1、containerPort # 容器端口
      docker run -p 80 -i -t ubuntu /bin/bash
    2、hostPort:containerPort # 主机端口:容器端口
      docker run -p 8080:80 -i -t ubuntu /bin/bash
    3、ip:containerPort # ip:容器端口
      docker run -p 0.0.0.0:80 -i -t ubuntu /bin/bash
    4、ip:hostPort:containerPort # 主机ip:主机端口:容器端口
      docker run -p 0.0.0.0:8080:80 -i -t ubuntu /bin/bash
13、查看删除镜像
  a)docker images [OPTIONS] [REPOSITORY]
    -a,--all=false
    -f,--filter=[] # 显示时的过滤条件
    --no-trunc=false # 不截断镜像ID
    -q,--quiet=false # 只显示镜像ID
  b)查看镜像:docker inspect [OPTIONS] CONTAINER|IMAGE
    -f,--format=""
  c)删除镜像:docker rmi [OPTIONS] IMAGE [IMAGE...]
    -f,--force=false # Force removal of the image
    --no-prune=false # Do not delete untagged parents
14、获取和推送镜像
  a)Docker Hub
    https://registry.hub.docker.com
  b)docker search [OPTIONS] TERM
    --automated=false # Only show automated builds
    --no-trunc=false # Don't truncate output
    -s,--stars=0 # Only displays with at least x stars
    # 最多返回25个结果
  c)拉取镜像:docker pull [OPTIONS] NAME[:TAG]
  d)加速pull,push镜像
    1、使用--registry-mirror选项
      修改:/etc/default/docker
      添加:DOCKER_OPTS = "--registry-mirror=http://MIRROR-ADDR"
15、构建镜像
  a)docker commit # 通过容器构建
    1、docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
      -a,--author="" # Author
      -m,--message="" # Commit message
      -p,--pause=true # Pause container during commit
  b)docker bulid # 通过Dockerfile文件构建
    1、创建Dockerfile
    2、使用docker build命令
      docker build [OPTIONS] PATH | URL | -
      --force-rm=false
      --no-cache=false
      -q,--quiet=false
      --rm=true
      -t,--tag=""
16、Docker的远程访问
  a)需要第二台安装Docker的服务器
  b)修改Docker守护进程启动选项,区别服务器
  c)保证Client API与Server API版本一致
  d)修改服务器端(客户端)配置
    1、修改Docker守护进程启动选项
      -H tcp://host:port
      unix:///path/to/socket
      fd://* or fd://socketfd
    2、守护进程默认配置:
      -H unix:///var/run/docker.sock
    3、使用环境变量DOCKER_HOST
      export DOCKER_HOST="tcp://10.211.55.5:2375"
17、制作镜像

17.1、Docketfile指令
  a)FROM
    格式:
      FROM <image>
      FROM <image>:<tag>
    注意:
      已存在的镜像
      基础镜像
      必须是第一条非注释指令
  b)MAINTAINER<name>
    指定镜像的作者信息,包含镜像的所有者和联系信息
  c)RUN
  格式:
    RUN <command> (shell模式)
    RUN ["executable","param1","param2"] (exec模式)
  d)EXPOSE <port> [<port>...]
  e)CMD
    格式:
      CMD ["executable","param1","param2"] (exec模式)
      CMD command param1 param2 (shell模式)
      CMD ['param1','param2'] (作为ENTRYPOINT指令的默认参数)
  f)ENTRYPOINT
    格式:
      ENTRYPOINT ['executable','param1','param2'] (exec模式)
      ENTRYPOINT command param1 param2 (shell模式)
    注意:
      可以使用docker run --entrypoint 覆盖
  h)ADD <src>...<dest>
     ADD ["<src>"..."<dest>"] (使用于文件路径中有空格的情况)
  i)COPY <src>...<src>
     COPY ["<src>"..."<dest>"] (适用于文件路径中有空格的情况)
  j)ADD vs COPY
     ADD包含类似tar的解压功能
       如果单纯复制文件,Docker推荐使用COPY
  k)VOLUME ["/data"]
  l)WORKDIR /path/to/workdir
  m)ENV <key> <value>
    ENV <key>=<value>...
  n)USER daemon
    USER nginx
  o)ONBUILD [INSTRUCTION]
    # 镜像触发器
    # 当一个镜像被其他镜像作为基础镜像时执行

17.2、基于容器制作

docker commit

(1)格式:

Usage: docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]

(2)Options 参数

  • -a,作者(例如,“along <along@along.com>”)
  • -c,修改Dockerfile指令应用于创建的镜像
  • -m,提交消息
  • -p,在提交期间暂停容器(默认为true)

(3)示例1:简单的基于容器创建一个新的镜像

① 先运行一个容器

[root@along ~]# docker run --name b1 -it busybox
/ # ls /
bin   dev   etc   home  proc  root  sys   tmp   usr   var
/ # mkdir -p /date/html
/ # echo "<h1>busybox httpd server</h1>" > /date/html/index.html
/ # cat /date/html/index.html
<h1>busybox httpd server</h1>

② 不用退出这个容器,另起终端在b1容器基础上,制作新镜像

[root@along ~]# docker commit -p b1
sha256:3a6523b08bea7eb339ae04cc8a98caabfd46fbd27ccf31409cc3e8a764effdc1
[root@along ~]# docker image ls
REPOSITORY               TAG                 IMAGE ID            CREATED             SIZE
<none>                   <none>              bf29b97ba38d        7 seconds ago       1.15 MB

③ 给新制作的镜像打标签

[root@along ~]# docker tag bf29b97ba38d along/httpd:v0.1
[root@along ~]# docker image ls
REPOSITORY               TAG                 IMAGE ID            CREATED             SIZE
along/httpd              v0.1                bf29b97ba38d        39 seconds ago      1.15 MB

④ 可以对同一个镜像,再打标签

[root@along ~]# docker tag along/httpd:v0.1 along/httpd:latest
[root@along ~]# docker image ls
REPOSITORY               TAG                 IMAGE ID            CREATED              SIZE
along/httpd              latest              bf29b97ba38d        About a minute ago   1.15 MB
along/httpd              v0.1                bf29b97ba38d        About a minute ago   1.15 MB

⑤ 删除同一镜像的标签,只是把这个镜像的标签去掉,只到删除这个镜像的最后一个标签,此镜像才会被删除

[root@along ~]# docker image rmi along/httpd:latest
Untagged: along/httpd:latest
[root@along ~]# docker image ls
REPOSITORY               TAG                 IMAGE ID            CREATED              SIZE
along/httpd              v0.1                bf29b97ba38d        About a minute ago   1.15 MB

⑥ 基于新的镜像运行一个容器,验证是否是基于b1创建成功的

[root@along ~]# docker run --name b2 -it along/httpd:v0.1
/ # cat /date/html/index.html
<h1>busybox httpd server</h1>
/ # exit

⑦通过容器构建镜像

docker commit -a "liugp" -m "elasticsearch构建镜像"  0ea5ad7d5917 mylampp-elasticsearch:v2

⑧通过镜像生成容器(例子)

# -p  :  端口映射
# -d  :  后台执行
# -v  :  挂载点
# --privileged  :  大约在0.6版,privileged被引入docker。使用该参数,container内的root拥有真正的root权限。
否则,container内的root只是外部的一个普通用户权限。
privileged启动的容器,可以看到很多host上的设备,并且可以执行mount。
甚至允许你在docker容器中启动docker容器。

docker run -d -p 80:80 -p 8087:8087 -p 3306:3306 -p 22:22 -p 9100:9100 -p 9200:9200 -p 9300:9300 -p 5601:5601 --name lampp-es -v /usr/local/html/mylampp-elacticsearch:/usr/local/html/mylampp-elasticsearch --privileged=true 792bbd88688e

 

(4)示例2:基于容器创建新的镜像,并修改执行命令CMD

  ① 基于容器b1创建新的镜像,并修改命令为执行httpd服务

[root@along ~]# docker commit -a "Along <along@along.com>" -c 'CMD ["/bin/httpd","-f","-h","/date/html"]' -p b1 along/httpd:v0.2
sha256:2291d0e5800e53e120fad58043e97cbf8197f7db2aa1111508603fa3c16982f2

注解:busybox 中httpd 语法

  •  -f:不运行为守护进程,在前台运行
  •  -h:指定httpd运行的主目录

② 运行新的镜像v0.2

[root@along ~]# docker run --name b3 -d along/httpd:v0.2
43e8731be7abd34a9b332c84bc622a1ef8707dc94465d3639db194c0b504cc42

③ 验证成功

[root@along ~]# docker inspect b3 |grep "IPAddress"
            "SecondaryIPAddresses": null,
            "IPAddress": "172.17.0.3",
                    "IPAddress": "172.17.0.3"
[root@along ~]# curl 172.17.0.3
<h1>busybox httpd server</h1>

17.3、了解Docker Registry

  3.1 介绍

  •  registry 用于保存docker 镜像,包括镜像的层次结构和元数据。
  •  启动容器时,docker daemon会试图从本地获取相关的镜像;本地镜像不存在时,其将从registry中下载该镜像并保存到本地;
  •  拉取镜像时,如果不知道registry仓库地址,默认从Docker Hub搜索拉取镜像

  3.2 分类

  • Sponsor Registry第三方的registry,供客户和docker社区使用;
  • mirror Registry第三方的registry,只让客户使用;如docker cn和阿里云的镜像加速器;
  • vendor Registry服务商的registry,由发布docker镜像的供应商提供的registry;如红帽提供的专有的,收费提供;
  • private Registry通过设有防火墙和额外的安全层的私有实体提供的registry;自建的registry,在本地搭建registry,节省带宽

  3.3 registry组成(repository和index)

  (1)Repository

    • 由特定的docker镜像的所有迭代版本组成的镜像仓库;
    • 一个registry中可以存在多个repository:
    • repository可分为“顶层仓库”和“用户仓库”
    • 用户仓库名称格式为“用户名/仓库名”
    • 每个仓库可以包含多个Tag(标签),每个标签对应一个镜像

  (2)Index

    • 维护用户账户、镜像的校验以及公共命名空间的信息
    • 相当于为registry提供了一个完成用户认证等功能的检索接口

  3.4 拉取仓库镜像的格式

docker pull <registry>[:<port>]/[<namespace>/]<name>:<tag>
  •  registry:仓库服务器地址:不指定默认是docker hub
  •  port:端口;默认是443,因为是https协议
  •  namespace:名称空间,指是哪个用户的仓库,如果是顶层仓库,可省
  •  name:仓库名
  •  tag:标签名;默认是latest版本

  3.5 知名docker仓库

  例:docker pull quay.io/coreos/flannel:v0.10.0-amd64

17.4、将制作的镜像上传到自己的私有registry仓库中 

4.1、 创建自己的docker registry

(1)可以在docker hub上创建;但注册docker hub需要***;

  

(2)也可以在阿里云上https://cr.console.aliyun.com/cn-hangzhou/repositories创建自己的docker仓库

① 创建镜像仓库

② 选择创建本地仓库

③ 点击管理,会有操作指南,大家跟着操作即可,这里我就不再演示了

4.2.1 登录docker仓库

[root@along ~]# docker login -u alongedu
Password:
Login Succeeded

4.2.2 将镜像打标签,对应自己的registry

[root@along ~]# docker tag busybox:latest alongedu/httpd:v0.1

4.2.3 push上传自己的镜像

[root@along ~]# docker push alongedu/httpd:v0.1
The push refers to a repository [docker.io/alongedu/httpd]
23bc2b70b201: Pushed
v0.1: digest: sha256:cbcde3595079b1f7a6b046e96e7547fe786d5c2c8eba678bc260161bc01b8dbe size: 527

4.3.1 登录阿里云docker registry:

$ sudo docker login --username=登录名 registry.cn-hangzhou.aliyuncs.com

4.3.2 从Registry中拉取镜像

$ sudo docker pull registry.cn-hangzhou.aliyuncs.com/liugp/mylampp:[镜像版本号]

4.3.3 将镜像推送到Registry

$ sudo docker login --username=登录名 registry.cn-hangzhou.aliyuncs.com
$ sudo docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/liugp/mylampp:[镜像版本号]
$ sudo docker push registry.cn-hangzhou.aliyuncs.com/liugp/mylampp:[镜像版本号]

4.3.4 示例

使用"docker tag"命令重命名镜像,并将它通过专有网络地址推送至Registry。

$ sudo docker images
REPOSITORY                                                         TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
registry.aliyuncs.com/acs/agent                                    0.7-dfb6816         37bb9c63c8b2        7 days ago          37.89 MB
$ sudo docker tag 37bb9c63c8b2 registry-vpc.cn-hangzhou.aliyuncs.com/acs/agent:0.7-dfb6816

使用"docker images"命令找到镜像,将该镜像名称中的域名部分变更为Registry专有网络地址。

$ sudo docker push registry-vpc.cn-hangzhou.aliyuncs.com/acs/agent:0.7-dfb6816

4.4 在自己的私有仓库验证

例1:

FROM centos
MAINTAINER liugp<2920992033@qq.com>

#把宿主机当前的上下文的c.txt拷贝到容器的/usr/local路径下
COPY c.txt /usr/local/cincontainer.txt
#把java与tomcat添加到容器中
ADD jdk-10.0.2_linux-x64_bin.tar.gz /usr/local/
ADD apache-tomcat-9.0.11.tar.gz /usr/local/
#安装vim编辑器
RUN yum -y install vim
#设置工作访问的时候的WORKDIR,登录落脚点
ENV MYPATH /usr/local
WORKDIR $MYPATH
#配置java与tomcat环境变量
ENV JAVA_HOME /usr/local/jdk-10.0.2
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINE_HOME /usr/local/apache-tomcat-9.0.11
ENV CATALINE_BASE /usr/local/apache-tomcat-9.0.11
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINE_HOME/lib:$CATALINE_HOME/bin
#容器运行时监听的端口
EXPOSE 8080
#启动时运行tomcat
# ENTRYPOINT  ["/usr/local/apache-tomcat-9.0.11/bin/startup.sh"]
# CMD  ["/usr/local/apache-tomcat-9.0.11/bin/startup.sh","run"]
CMD /usr/local/apache-tomcat-9.0.11/bin/startup.sh && tail -f /usr/local/apache-tomcat-9.0.11/bin/logs/catalina.out



# docker build -t liugptomcat9 .
# docker run -d -p 9080:8080 --name myt9 -v /Users/liugp/mydocker/tomcat9/test:/usr/local/apache-tomcat-9.0.11/webapps/test -v /Users/liugp/mydocker/tomcat9/tomcat9logs/:/usr/local/apache-tomcat-9.0.11/webapps/logs --privileged=true liugptomcat9


#mysql
docker run -p 12345:3306 --name mysql -v /Users/liugp/mydocker/mysql/conf:/etc/mysql/conf.d -v /Users/liugp/mydocker/mysql/logs:/logs -v /Users/liugp/mydocker/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.6

#redis
docker run -p 6379:6379
-v /Users/liugp/mydocker/myredis/data:/data
-v /Users/liugp/mydocker/myredis/conf/redis.conf:/usr/local/redis/redis.conf
-d redis:3.2 redis-server /usr/local/etc/redis/redis.conf
--appendonly yes

例2:

FROM centos
MAINTAINER liugp<2920992033@qq.com>

#把宿主机当前的上下文的c.txt拷贝到容器的/usr/local路径下
COPY c.txt /usr/local/cincontainer.txt
#把java与tomcat添加到容器中
ADD jdk-10.0.2_linux-x64_bin.tar.gz /usr/local/
ADD apache-tomcat-9.0.11.tar.gz /usr/local/
#安装vim编辑器
RUN yum -y install vim
#设置工作访问的时候的WORKDIR,登录落脚点
ENV MYPATH /usr/local
WORKDIR $MYPATH
#配置java与tomcat环境变量
ENV JAVA_HOME /usr/local/jdk-10.0.2
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINE_HOME /usr/local/apache-tomcat-9.0.11
ENV CATALINE_BASE /usr/local/apache-tomcat-9.0.11
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINE_HOME/lib:$CATALINE_HOME/bin
#容器运行时监听的端口
EXPOSE 8080
#启动时运行tomcat
# ENTRYPOINT  ["/usr/local/apache-tomcat-9.0.11/bin/startup.sh"]
# CMD  ["/usr/local/apache-tomcat-9.0.11/bin/startup.sh","run"]
CMD /usr/local/apache-tomcat-9.0.11/bin/startup.sh && tail -f /usr/local/apache-tomcat-9.0.11/bin/logs/catalina.out



# docker build -t liugptomcat9 .
# docker run -d -p 9080:8080 --name myt9 -v /Users/liugp/mydocker/tomcat9/test:/usr/local/apache-tomcat-9.0.11/webapps/test -v /Users/liugp/mydocker/tomcat9/tomcat9logs/:/usr/local/apache-tomcat-9.0.11/webapps/logs --privileged=true liugptomcat9


#mysql
docker run -p 12345:3306 --name mysql -v /Users/liugp/mydocker/mysql/conf:/etc/mysql/conf.d -v /Users/liugp/mydocker/mysql/logs:/logs -v /Users/liugp/mydocker/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.6

#redis
docker run -p 6379:6379 -v /Users/liugp/mydocker/myredis/data:/data -v /Users/liugp/mydocker/myredis/conf/redis.conf:/usr/local/etc/redis/redis.conf -d redis:3.2 redis-server /usr/local/etc/redis/redis.conf --appendonly yes


#阿里云镜像下载docker
官网:yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
阿里云:yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

例3:zip包(SpringBoot项目)镜像部署(docker 打包/导入

1、拉取tomcat镜像

docker pull java:8

2、上传需要部署的zip包(以hello.zip为例)到自定义的工作目录下。

3、在上个步骤创建的工作目录下创建Dockerfile文件。将zip包解压,和Dockerfile文件放在同一目录下。Dockerfile文件内容如下:
from java:8
 
ENV LANG C.UTF-8
 
ENV TZ=Asia/Shanghai
 
ENV JAVA_OPTS=" -Dspring.config.location=/hello/application.properties"
 
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
 
ADD hello.zip  .
 
RUN unzip hello.zip
 
RUN chmod +x /hello/bin/start.sh
 
RUN chmod +x /hello /bin/stop.sh
 
CMD cd /hello /bin/&&./start.sh
View Code

4、创建镜像(注:-t 表示为该镜像起名称,另外,构建命令后面有个英文实心点,表示当前目录。)

docker build -t hello .

5、通过docker images可以看到该镜像已经创建成功了

docker images | grep hello

6、运行自己的镜像(注: -d:表示在后台运行该镜像,按ctrl+C不会终止该程序;-p:表示指定本机的端口对应容器中的端口。-it表示以交互模式运行容器并分配伪终端。uap-service项目内置了一个tomcat容器,在其application.properties配置文件中server.port=8080。若设置server.port=xxx,则命令相应位置为30803:xxx)(打开伪终端,进去容器)

docker run -p 30803:8080 hello

7、docker镜像导出,tar镜像包可以拷贝到其他机器docker环境中加载

docker save hello -o hello.tar

8、docker镜像加载

docker load -i hello.tar

9、测试示例

 http://ip:30803/hello

17.4、docker exec 与 docker attach 区别        

    1、Docker attach可以attach到一个已经运行的容器的stdin,然后进行命令执行的动作。  但是需要注意的是,如果从这个stdin中exit,会导致容器的停止。

    2、Docker exec

      关于-i、-t参数

        1、可以看出只用-i时,由于没有分配伪终端,看起来像pipe执行一样。但是执行结果、命令  返回值都可以正确获取。

          例:docker exec -i bb2 /bin/sh

        2、使用-it时,则和我们平常操作console界面类似。而且也不会像attach方式因为退出,导致  整个容器退出。  这种方式可以替代ssh或者    nsenter、nsinit方式,在容器内进行操作。


18、Docker容器的网络连接
  a)Docker容器的网络基础
    1、Linux虚拟网桥的特点:
      可以设置IP地址
      相当于拥有一个隐藏的虚拟网卡
    2、docker0的地址划分:
      IP: 172.17.42.1 子网掩码:255.255.0.0
      MAC:02:42:ac:11:00:00 到 02:42:ac:11:ff:ff
      总共提供了65534个地址
    3、修改docker0地址:
      sudo ifconfig docker0 192.168.200.1 netmask 255.255.255.0
    4、更改docker守护进程的启动配置:
      /etc/default/docker 中添加DOCKER_OPS
      -b=br0

  b)Docker容器的互联
    1、允许所有容器互联
    2、拒绝容器间互联
    3、允许特定容器的链接
    4、Docker守护进程的启动选项
      --icc=false
    5、允许特定容器间的连接
      Docker守护进程的启动选项
      --icc=false --iptables=true
      --link
  c)Docker容器与外部网络的连接
    1、ip_forward
      --ip-forward=true

    2、iptables
      filter表中包含的链:
        INPUT,FORWARD,OUTPUT
    3、允许端口映射访问
    4、限制ip访问容器
19、Docker容器的数据管理
  a)Docker容器的数据卷
    1、数据卷是经过特殊设计的目录,可以绕过联合文件系统(UFS),为一个或多个容器提供访问
    2、数据卷设计的目的,在于数据的永久化,它完全独立于容器的生命周期,因此,Docker不会在容器删除时删除挂载的数据卷,也不会存在类似的垃圾回收机制,对容器引用的数据卷进行处理
    3、数据卷在容器启动时初始化,如果容器使用的镜像在挂载点包含了数据,这些数据会拷贝到新初始化的数据卷中。
    4、数据卷可以在容器之间共享和重用
    5、可以对数据卷里的内容直接进行修改
    6、数据卷的变化不会影响镜像的更新
    7、卷会一直存在,即使挂载数据卷的容器已经被删除
  b)Docker的数据卷容器
    1、为容器添加数据卷
      sudo docker run -V ~/datavolume:/data -it ubuntu /bin/bash
    2、sudo docker run -V ~/datavolume:/data:ro -it ubuntu /bin/bash
    3、使用Dockerfile构建包含数据卷的镜像
      Dockerfile指令:VOLUME ["/data"]
    4、挂载数据卷容器的方法
      docker run --volumes-from [CONTAINER NAME]

  c)Docker数据卷的备份和还原
20、Docker容器的跨主机连接
  a)使用网桥实现跨主机容器连接
    优点:
      配置简单,不依赖第三方软件
    缺点:
      与主机在同网段,需要小心划分IP地址
      需要有网段控制权,在生成环境中不易实现
      不容易管理
      兼容性不佳
  b)使用Open vSwitch实现跨主机容器连接
  c)使用weave实现跨主机容器连接
21、Container的核心技术
  a)CGroups 限制容器的资源使用
    1、Linux内核提供的限制,记录和隔离进程组所使用的资源,由Google的工程师提出,后来被整合到kernel
    2、通过不同的子系统(blkio,cpu,cpuacct等)来实现对不同资源使用的控制和记录
  b)Namespace机制,实现容器间的隔离
    1、pid,容器有自己的进程表和1号进程
    2、net,容器有自己独立的network info
    3、ipc,在ipc通信时候,需要加入额外信息来标识进程
    4、mnt,每个容器有自己唯一的目录挂载
    5、utc,每个容器有独立的hostname和domain
  c)chroot,文件系统的隔离 

22、docker容器配置ssh登入实录

22.1、准备工作

docker pull centos 下拉镜像
docker run centos:latest /bin/bash 启动容器

22.2、容器内部安装以下依赖

$ sudo yum -y install openssh-server
$ sudo yum -y install openssh-clients
$ /usr/sbin/sshd 启动
$ /usr/sbin/sshd restart 重启
passwd
  新密码
  确认新密码
ps:只有重置密码才能使用(如提示没有passwd这个命令行使用yum install passwd安装)和 ps -aux | grep sshd 查看sshd状态或者netstat -ant |grep 22也可以,ssh默认是端口号是22

22.3、完成后重启容器 

$ docker run -it -p 5000:22 contos:latest /bin/bash

22.4、ssh连接docker容器

$ ssh -p 5000 root@127.0.0.1

22.5、配置:

修改SSH配置文件以下选项,去掉#注释,将四个选项启用:

$ vi /etc/ssh/sshd_config

RSAAuthentication yes #启用 RSA 认证
PubkeyAuthentication yes #启用公钥私钥配对认证方式
AuthorizedKeysFile .ssh/authorized_keys #公钥文件路径(和上面生成的文件同)
PermitRootLogin yes #root能使用ssh登录

23、Docker-Compose

23.1、安装docker-Compose

目前有两种主流安装方式,笔者使用了第一种方式。

第一种

下载最新的docker-compose文件

curl -L https://github.com/docker/compose/releases/download/1.16.1/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose

下载完成后需要对/usr/local/bin/docker-compose目录进行赋权

chmod +x /usr/local/bin/docker-compose

测试结果

docker-compose --version
输出
docker-compose version 1.16.1, build 6d1ac21

第二种

通过pip方式安装

pip install docker-compose

23.2、卸载

第一种

rm /usr/local/bin/docker-compose

第二种

pip uninstall docker-compose

使用:docker-compos.yml

version: '2'

services:
  zoo1:
    # 依赖于wurstmeister/zookeeper镜像,本地无则自动下载
    image: wurstmeister/zookeeper
    restart: unless-stopped
    hostname: zoo1
    # 映射端口
    ports:
      - "2181:2181"
    # 容器名称
    container_name: zookeeper
  kafka1:
    # 依赖于wurstmeister/kafka镜像
    image: wurstmeister/kafka
    # 映射端口
    ports:
      - "9092:9092"
    # 目录挂载 【容器目录:宿主机目录】
    volumes:
      - /var/log/kafka/logs:/var/docker/kafka/logs
    # 配置环境变量
    environment:
      KAFKA_ADVERTISED_HOST_NAME: localhost
      KAFKA_ZOOKEEPER_CONNECT: "zoo1:2181"
      KAFKA_BROKER_ID: 1
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
      KAFKA_CREATE_TOPICS: "stream-in:1:1,stream-out:1:1"
    # 解决服务启动顺序问题,例如下面容器会先确定zoo1和redis两个服务,最后才启动kafka1服务
    depends_on:
      - zoo1
      - redis(实际无该容器)
    # 容器名称
    container_name: kafka
View Code

执行:

# -d 后台执行
docker-compose up -d

如果想单独启动一个服务,你可以:

docker-compose up -d 指定服务名称

例子:docker-compose up -d zoo1

服务排编案例

version: "3"
  services:
    # 指定服务名称
    #服务注册与发现中心
    simonEureka:
      image: simon/eureka-server:2.0.1-SNAPSHOT
      hostname: simonEureka
      ports:
        - "8100:8100"
    #配置中心    
    simonConfig:
      image: simon/config-server:2.0.1-SNAPSHOT
      hostname: simonConfig
      ports:
        - "8101:8101"
      depends_on:
        - simonEureka
      # always – 不管退出状态码是什么始终重启容器。当指定always时,docker daemon将无限次数地重启容器。容器也会在daemon启动时尝试重启,不管容器当时的状态如何。
      # no – 容器退出时不要自动重启。这个是默认值。
      # on-failure[:max-retries] – 只在容器以非0状态码退出时重启。可选的,可以退出docker daemon尝试重启容器的次数。
      # unless-stopped - 不管退出状态码是什么始终重启容器,不过当daemon启动时,如果容器之前已经为停止状态,不要尝试启动它。
      restart: always
    #路由网关  
    apigateway:
      image: simon/apigateway:2.0.1-SNAPSHOT
      ports:
        - "8102:8102"
      depends_on:
        - simonEureka
        - simonConfig
      restart: always
    #监控平台  
    admin:
      image: simon/admin:2.0.1-SNAPSHOT
      ports:
        - "8103:8103"
      depends_on:
        - simonEureka
        - simonConfig
      restart: always
View Code

这个时候我们服务器simon目录的文件应该如下:

apigateway:2.0.1-SNAPSHOT.jar
admin:2.0.1-SNAPSHOT.jar
config-server:2.0.1-SNAPSHOT.jar
eureka-server:2.0.1-SNAPSHOT.jar
docker-compose.yml

注意点

如果我们的yml文件不是docker-compose.yml时我们在进行服务排编是需要指定yml文件名称。

docker-compose -f docker-kafka.yml up -d

当我们遇到服务启动需要先后顺序时,我们可以对docker-compose.yml根据服务的先后顺序进行拆分。

常用的docker-compose命令

命令

描述

docker-compose up -d nginx 构建建启动nignx容器
docker-compose exec nginx bash 登录到nginx容器中
docker-compose down 删除所有nginx容器,镜像
docker-compose ps 显示所有容器
docker-compose restart nginx 重新启动nginx容器
docker-compose run --no-deps --rm php-fpm php -v 在php-fpm中不启动关联容器,并容器执行php -v 执行完成后删除容器
docker-compose build nginx 构建镜像
docker-compose build --no-cache nginx 不带缓存的构建
docker-compose logs nginx 查看nginx的日志
docker-compose logs -f nginx 验证(docker-compose.yml)文件配置,当配置正确时,不输出任何内容,当文件配置错误,输出错误信息
docker-compose pause nginx 暂停nignx容器
docker-compose unpause nginx 恢复ningx容器
docker-compose rm nginx 删除容器(删除前必须关闭容器)
docker-compose stop nginx 停止nignx容器
docker-compose start nginx 启动nignx容器

24、Docker私有仓库搭建

24.1、简介

  • 在 Docker 中,当我们执行 docker pull xxx 的时候 ,它实际上是从 registry.hub.docker.com 这个地址去查找,这就是Docker公司为我们提供的公共仓库。在工作中,我们不可能把企业项目push到公有仓库进行管理。所以为了更好的管理镜像,Docker不仅提供了一个中央仓库,同时也允许我们搭建本地私有仓库。这一篇介绍registryharbor两种私有仓库搭建。

一、registry 的搭建

Docker 官方提供了一个搭建私有仓库的镜像 registry ,只需把镜像下载下来,运行容器并暴露5000端口,就可以使用了。

  • --restart=always:docker重启会自动启动这个容器服务
docker run -d -v /opt/registry:/var/lib/registry -p 5000:5000 --restart=always --name myregistry registry
  • Registry服务默认会将上传的镜像保存在容器的/var/lib/registry,我们将主机的/opt/registry目录挂载到该目录,即可实现将镜像保存到主机的/opt/registry目录了。
  • 浏览器访问http://127.0.0.1:5000/v2,出现下面情况说明registry运行正常。
  • 修改配置:vi /etc/docker/daemon.json
  • "insecure-registries": ["192.168.182.135:5000"]

验证

  • 要通过docker tag将该镜像标志为要推送到私有仓库:
docker tag  hello-world localhost:5000/hello-world:latest
  • 通过 docker push 命令将 镜像 push到私有仓库中:
docker push localhost:5000/hello-world

  • 下载私有仓库的镜像,使用如下命令:
docker pull localhost:5000/镜像名:版本号
例如
docker pull localhost:5000/nginx:latest

二、harbor 的搭建

  • docker 官方提供的私有仓库 registry,用起来虽然简单 ,但在管理的功能上存在不足。 Harbor是一个用于存储和分发Docker镜像的企业级Registry服务器,harbor使用的是官方的docker registry(v2命名是distribution)服务去完成。harbor在docker distribution的基础上增加了一些安全、访问控制、管理的功能以满足企业对于镜像仓库的需求。

1、搭建

tar -xvf harbor-offline-installer-v1.9.4-rc1.tgz
  • 修改 harbor.yml

  • 需要注意的是,非 Mac 用户只需要 修改 harbor.cfg 中的 hostname ,就可以直接通过./install.sh 就可以构建镜像,并把服务启动起来。不需要 secretkey_path 和 下面 docker-compose.yml 的修改
  • 修改 docker-compose.yml
  • 因为harbor使用了很多目录挂载,Mac有很多目录是不允许挂载的,所以如果是Mac用户,需要修改docker-compose.yml 中的挂载目录,修改后的 docker-compose.yml 如下:
version: '3'
services:
  log:
    image: vmware/harbor-log:v1.2.2
    container_name: harbor-log 
    restart: always
    volumes:
      - ./log/:/var/log/docker/:z
    ports:
      - 127.0.0.1:1514:514
    networks:
      - harbor
  registry:
    image: vmware/registry:2.6.2-photon
    container_name: registry
    restart: always
    volumes:
      - ./data/registry:/storage:z
      - ./common/config/registry/:/etc/registry/:z
    networks:
      - harbor
    environment:
      - GODEBUG=netdns=cgo
    command:
      ["serve", "/etc/registry/config.yml"]
    depends_on:
      - log
    logging:
      driver: "syslog"
      options:  
        syslog-address: "tcp://127.0.0.1:1514"
        tag: "registry"
  mysql:
    image: vmware/harbor-db:v1.2.2
    container_name: harbor-db
    restart: always
    volumes:
      - ./data/database:/var/lib/mysql:z
    networks:
      - harbor
    env_file:
      - ./common/config/db/env
    depends_on:
      - log
    logging:
      driver: "syslog"
      options:  
        syslog-address: "tcp://127.0.0.1:1514"
        tag: "mysql"
  adminserver:
    image: vmware/harbor-adminserver:v1.2.2
    container_name: harbor-adminserver
    env_file:
      - ./common/config/adminserver/env
    restart: always
    volumes:
      - ./data/config/:/etc/adminserver/config/:z
      - ./data/secretkey:/etc/adminserver/key:z
      - ./data/:/data/:z
    networks:
      - harbor
    depends_on:
      - log
    logging:
      driver: "syslog"
      options:  
        syslog-address: "tcp://127.0.0.1:1514"
        tag: "adminserver"
  ui:
    image: vmware/harbor-ui:v1.2.2
    container_name: harbor-ui
    env_file:
      - ./common/config/ui/env
    restart: always
    volumes:
      - ./common/config/ui/app.conf:/etc/ui/app.conf:z
      - ./common/config/ui/private_key.pem:/etc/ui/private_key.pem:z
      - ./data/secretkey:/etc/ui/key:z
      - ./data/ca_download/:/etc/ui/ca/:z
      - ./data/psc/:/etc/ui/token/:z
    networks:
      - harbor
    depends_on:
      - log
      - adminserver
      - registry
    logging:
      driver: "syslog"
      options:  
        syslog-address: "tcp://127.0.0.1:1514"
        tag: "ui"
  jobservice:
    image: vmware/harbor-jobservice:v1.2.2
    container_name: harbor-jobservice
    env_file:
      - ./common/config/jobservice/env
    restart: always
    volumes:
      - ./data/job_logs:/var/log/jobs:z
      - ./common/config/jobservice/app.conf:/etc/jobservice/app.conf:z
      - ./data/secretkey:/etc/jobservice/key:z
    networks:
      - harbor
    depends_on:
      - ui
      - adminserver
    logging:
      driver: "syslog"
      options:  
        syslog-address: "tcp://127.0.0.1:1514"
        tag: "jobservice"
  proxy:
    image: vmware/nginx-photon:1.11.13
    container_name: nginx
    restart: always
    volumes:
      - ./common/config/nginx:/etc/nginx:z
    networks:
      - harbor
    ports:
      - 9090:80
      - 443:443
      - 4443:4443
    depends_on:
      - mysql
      - registry
      - ui
      - log
    logging:
      driver: "syslog"
      options:  
        syslog-address: "tcp://127.0.0.1:1514"
        tag: "proxy"
networks:
  harbor:
    external: false
View Code
  • 通过运行 install.sh 构建镜像,并把服务启动起来:
./install.sh

2、使用

  •  默认 admin 用户的密码为 Harbor12345 ,可以在 harbor.yml 进行修改。登录后如下:
  • 图中的项目是之前上传的 ,新部署的 Harbor 登录后项目下是空的。
  • 可以创建项目,创建用户,给项目分配用户等等,操作都很简单 。

3、上传镜像

  • 首先登录私有仓库,可以使用 admin 用户 ,也可以使用我们自己创建的具有上传权限的用户:
docker login -u admin -p Harbor12345 192.168.182.135:9090
  • 如果出现如下问题
  • [root@k8s-master harbor]# docker login -u admin -p Harbor12345 192.168.182.135:9090
    WARNING! Using --password via the CLI is insecure. Use --password-stdin.
    Error response from daemon: Get https://192.168.182.135:9090/v2/: http: server gave HTTP response to HTTPS client
  • 解决办法是:在docker server启动的时候,增加启动参数,默认使用HTTP访问:

  • $ vim /etc/docker/daemon.json
  • "insecure-registries": ["192.168.182.135:9090"]

  • 或者

     $  vim /usr/lib/systemd/system/docker.service

  • --insecure-registry  ip:9090
  • # 修改好后重启docker 服务
    
    systemctl daemon-reload 
    
    systemctl restart docker
  • 再执行./install.sh
  • 要通过docker tag将该镜像标志为要推送到私有仓库,例如:
docker tag nginx:latest 127.0.0.1:9090/library/hello-world:latest
  • 上传镜像:
docker push 127.0.0.1:9090/library/hello-world:latest

最后提供两个命令:

# 删除所有的容器
docker container rm -f `docker container ls -a -q`

# 删除所有的镜像
docker rmi -f `docker image ls -a -q`

25、docker network

一、网络类型:

1)host:

  • 容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口,共用宿主机网络
  • 示例:
  • # --net等价于--network
    docker run --name=nginx_host --net=host -p 80:80 -d nginx

2)none

  • 该模式将容器放置在它自己的网络栈中,但是并不进行任何配置。实际上,该模式关闭了容器的网络功能,在以下两种情况下是有用的:容器并不需要网络(例如只需要写磁盘卷的批处理任务)。

3)Container

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

4)Bridge

  • 相当于Vmware中的Nat模式,容器使用独立network Namespace,并连接到docker0虚拟网卡(默认模式)。通过docker0网桥以及Iptables nat表配置与宿主机通信;bridge模式是Docker默认的网络设置,此模式会为每一个容器分配Network Namespace、设置IP等,并将一个主机上的Docker容器连接到一个虚拟网桥上。

5)overlay

  • 在docker1.7代码进行了重构,单独把网络部分独立出来编写,所以在docker1.8新加入的一个overlay网络模式。Docker对于网络访问的控制也是在逐渐完善的。
  • Overlay网络是指在不改变现有网络基础设施的前提下,通过某种约定通信协议,把二层报文封装在IP报文之上的新的数据格式。这样不但能够充分利用成熟的IP路由协议进程数据分发;而且在Overlay技术中采用扩展的隔离标识位数,能够突破VLAN的4000数量限制支持高达16M的用户,并在必要时可将广播流量转化为组播流量,避免广播数据泛滥。

以上都是不用动手的,真正需要配置的是自定义网络。

Docker内置这三个网络,运行容器时,你可以使用该--network标志来指定容器应连接到哪些网络。

[root@k8s-master harbor]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
551153be84c3        bridge              bridge              local
3db96ea4929a        host                host                local
5a81d6adcc31        none                null                local

我们在使用docker run创建Docker容器时,可以用 --net 选项指定容器的网络模式,Docker可以有以下4种网络模式:

  1. host模式:使用 --net=host 指定。
  2. none模式:使用 --net=none 指定。
  3. bridge模式:使用 --net=bridge 指定,默认设置。
  4. container模式:使用 --net=container:NAME_or_ID 指定。

二、Bridge模式

2.1、Bridge模式的拓扑

  • 当Docker server启动时,会在主机上创建一个名为docker0的虚拟网桥,此主机上启动的Docker容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。接下来就要为容器分配IP了,Docker会从RFC1918所定义的私有IP网段中,选择一个和宿主机不同的IP地址和子网分配给docker0,连接到docker0的容器就从这个子网中选择一个未占用的IP使用。如一般Docker会使用172.17.0.0/16这个网段,并将172.17.0.1/16分配给docker0网桥(在主机上使用ifconfig命令是可以看到docker0的,可以认为它是网桥的管理接口,在宿主机上作为一块虚拟网卡使用)。单机环境下的网络拓扑如下,主机地址为10.10.0.186/24。

2.2、Docker:网络模式详解

Docker完成以上网络配置的过程大致是这样的:

  • 在主机上创建一对虚拟网卡veth pair设备。veth设备总是成对出现的,它们组成了一个数据的通道,数据从一个设备进入,就会从另一个设备出来。因此,veth设备常用来连接两个网络设备。
  • Docker将veth pair设备的一端放在新创建的容器中,并命名为eth0。另一端放在主机中,以veth65f9这样类似的名字命名,并将这个网络设备加入到docker0网桥中,可以通过brctl show命令查看。
$ brctl show
bridge name     bridge id               STP enabled     interfaces
docker0         8000.02425f21c208       no
  • 从docker0子网中分配一个IP给容器使用,并设置docker0的IP地址为容器的默认网关
$ docker network inspect bridge
[
    {
        "Name": "bridge",
        "Id": "551153be84c397f3f73c76aac661357d68d5ea9c30860d2a3e54c1121bc7674e",
        "Created": "2019-12-30T16:33:31.47575594+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "d08987f315f4f9f4ca94359ba162372337879494fa134be4f88c50ba03e3e7c9": {
                "Name": "myregistry",
                "EndpointID": "ca86a43ebc4bbb4158cef029647890b483723fb32d953f3a048ce4dfbd67e6cf",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        },
        "Labels": {}
    }
]
View Code

2.3、bridge模式下容器的通信

  • 在bridge模式下,连在同一网桥上的容器可以相互通信(若出于安全考虑,也可以禁止它们之间通信,方法是在DOCKER_OPTS变量中设置–icc=false,这样只有使用–link才能使两个容器通信)。
  • Docker可以开启容器间通信(意味着默认配置--icc=true),也就是说,宿主机上的所有容器可以不受任何限制地相互通信,这可能导致拒绝服务攻击。进一步地,Docker可以通过--ip_forward和--iptables两个选项控制容器间、容器和外部世界的通信。
  • 容器也可以与外部通信,我们看一下主机上的Iptable规则,可以看到这么一条
  • -A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
  • 这条规则会将源地址为172.17.0.0/16的包(也就是从Docker容器产生的包),并且不是从docker0网卡发出的,进行源地址转换,转换成主机网卡的地址。

  • 举例说明:假设主机有一块网卡为eth0,IP地址为10.10.101.105/24,网关为10.10.101.254。从主机上一个IP为172.17.0.1/16的容器中ping百度(180.76.3.151)。IP包首先从容器发往自己的默认网关docker0,包到达docker0后,也就到达了主机上。然后会查询主机的路由表,发现包应该从主机的eth0发往主机的网关10.10.105.254/24。接着包会转发给eth0,并从eth0发出去(主机的ip_forward转发应该已经打开)。这时候,上面的Iptable规则就会起作用,对包做SNAT转换,将源地址换为eth0的地址。这样,在外界看来,这个包就是从10.10.101.105上发出来的,Docker容器对外是不可见的。
  • 那么,外面的机器是如何访问Docker容器的服务呢?我们首先用下面命令创建一个含有web应用的容器,将容器的80端口映射到主机的80端口。

  • $ docker run --name=nginx_bridge --net=bridge -p 80:80 -d nginx
  • 然后查看Iptable规则的变化,发现多了这样一条规则:
  • -A DOCKER ! -i docker0 -p tcp -m tcp --dport 80 -j DNAT --to-destination 172.17.0.2:80
    此条规则就是对主机eth0收到的目的端口为80的tcp流量进行DNAT转换,将流量发往172.17.0.2:80,也就是我们上面创建的Docker容器。所以,外界只需访问10.10.101.105:80就可以访问到容器中的服务。

    除此之外,我们还可以自定义Docker使用的IP地址、DNS等信息,甚至使用自己定义的网桥,但是其工作方式还是一样的。

2.4、自定义网络

1)bridge:

  • 一个bridge网络是Docker中最常用的网络类型。桥接网络类似于默认bridge网络,但添加一些新功能并删除一些旧的能力。以下示例创建一些桥接网络,并对这些网络上的容器执行一些实验。
$ docker network create --driver bridge new_bridge
  • 创建网络后,可以看到新增加了一个网桥(172.18.0.1)。

 2)Macvlan

  • Macvlan是一个新的尝试,是真正的网络虚拟化技术的转折点。Linux实现非常轻量级,因为与传统的Linux Bridge隔离相比,它们只是简单地与一个Linux以太网接口或子接口相关联,以实现网络之间的分离和与物理网络的连接。
  • Macvlan提供了许多独特的功能,并有充足的空间进一步创新与各种模式。这些方法的两个高级优点是绕过Linux网桥的正面性能以及移动部件少的简单性。删除传统上驻留在Docker主机NIC和容器接口之间的网桥留下了一个非常简单的设置,包括容器接口,直接连接到Docker主机接口。由于在这些情况下没有端口映射,因此可以轻松访问外部服务。

Macvlan Bridge模式示例用法

  • Macvlan Bridge模式每个容器都有唯一的MAC地址,用于跟踪Docker主机的MAC到端口映射。 Macvlan驱动程序网络连接到父Docker主机接口。示例是物理接口,例如eth0,用于802.1q VLAN标记的子接口eth0.10(.10代表VLAN 10)或甚至绑定的主机适配器,将两个以太网接口捆绑为单个逻辑接口。 指定的网关由网络基础设施提供的主机外部。 每个Macvlan Bridge模式的Docker网络彼此隔离,一次只能有一个网络连接到父节点。每个主机适配器有一个理论限制,每个主机适配器可以连接一个Docker网络。 同一子网内的任何容器都可以与没有网关的同一网络中的任何其他容器进行通信macvlan bridge。 相同的docker network命令适用于vlan驱动程序。 在Macvlan模式下,在两个网络/子网之间没有外部进程路由的情况下,单独网络上的容器无法互相访​​问。这也适用于同一码头网络内的多个子网。
  • 在以下示例中,eth0在docker主机网络上具有IP地址172.16.86.0/24,默认网关为172.16.86.1,网关地址为外部路由器172.16.86.1。
  • 创建macvlan网络并运行附加的几个容器:
  • 利用macvlan实现跨宿主机容器通信
# 两台宿主机上都执行
docker network create \
  --driver macvlan \
  --subnet=10.10.0.0/24 \
  --gateway=10.10.0.253 \
  -o parent=ens33 macvlan10

# 一台宿主机上执行
docker run --net=macvlan10 -it --name=macvlan_test1 --ip=10.10.0.189 busybox /bin/sh

# 另一台宿主机上执行
docker run --net=macvlan10 -it --name=macvlan_test2 --ip=10.10.0.190 busybox /bin/sh

# 查看:ip add show
# 通过ping测试
缺点:不能自动校验ip冲突,得人为区分,只能容器之间访问,而且无法访问到外网,overlay可以补足

3)overlay 

3.1、Docker 原生Overlay 网络工作流程

网卡设备

  • Container eth0:eth0它是Overlay网络分配的唯一的IP地址,它是veth pair虚拟设备对,作用是实现点对点的通信,通过桥接到br0这个网桥中,可以实现不同 NameSwitch之间容器进行通信。
  • br0:它是Overlay默认创建的网桥。
  • VETP:对VXLAN数据包的封装与街封装。
  • Container eth1:eth1是容器主机的默认网络,主要提供容器访问外网所提供的服务,走的默认docker网络架构,只不过他创建了docker_gwbridge这个网桥。
  • docker_gwbridge:docker_gwbridge是容器所创建的网桥它替代了docker0的服务。
  • eth0:真机网卡与外界网卡连接得真机网卡,它用来转发,容器VXLAN与NAT两种网卡类型的数据包到指定的对端节点。

3.2、发送数据包流程

容器Container1 发送数据包 到容器 Container2。

  • 1、容器Container1会通过Container eth0 将这个数据包发送到 10.0.0.1 的网关。
  • 2、网关将数据包发送出去后到达b20网桥。
  • 3、b20网桥针对VXLAN设备,主要用于捕获对外的数据包通过VETP进行数据包封装。
  • 4、封装好将VXLAN格式数据包交给eth0,通过UDP方式交给Container2的eth0。
  • 5、Container2收到数据包后通过VETP将数据包解封装。
  • 6、网桥通过网关将解封装的数据包转发给Container eth0,完毕通信。

3.3、利用overlay实现跨宿主机容器通信

# 启动consul,统一配置管理服务,可以防止ip冲突问题,随便在哪台机子上执行
docker run -d -p 8500:8500 -h consul --name consul progrium/consul -server -bootstrap

# consul:kv类型的存储数据库(key:value)
# docker01、docker02上都执行:
$ vim /etc/docker/daemon.json
{
    "hosts":["tcp://0.0.0.0:2375","unix:///var/run/docker.sock"],
    "cluster-store": "consule://192.168.182.136:8500",
    "cluster-advertise": "192.168.182.136:2375"
}
# 或者
$ vim /lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H fd:
// --containerd=/run/containerd/containerd.sock -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --cluster-store consul://192.168.182.136:8500 --cluster-advertise 192.168.182.136:2375 # 重启 systemctl daemon-reload systemctl restart docker # 只需要在一台宿主机上执行,创建overlay网络,只要配置了上面的,会自动同步到对应的主机上 docker network create -d overlay --subnet 172.16.0.0/24 --gateway 172.16.0.254 ol1 3)启动容器测试,name不能一样 docker run -it --net=ol1 --name=overlay_test1 busybox /bin/sh docker run -it --net=ol1 --name=overlay_test2 busybox /bin/sh
posted @ 2019-07-12 23:04  大数据老司机  阅读(497)  评论(0编辑  收藏  举报