Docker学习笔记--(超详细)

    # Docker的基本概念                                                                                        

        容器技术是一种全新意义上的虚拟化技术,按分类或者实现方式来说,其应该属于操作系统虚拟化的范畴,也就是在由操作系统提供虚拟化的支持。

所谓容器技术,指的是操作系统自身支持一些接口,能够让应用程序间可以互不干扰的独立运行,并且能够对其在运行中所使用的资源进行干预。当然,目前来说容器技术还没有一个严格的定义,其实现方式也各有不同,所以这里只能算是我的一点小小总结归纳。

由于应用程序的运行被隔离在了一个独立的运行环境之中,这个独立的运行环境就好似一个容器,包裹住了应用程序,这就是容器技术名字的由来。

        Docker 项目是一个由 Go 语言实现的容器引擎,它最初由 dotCloud 这家做云服务的公司在 2013 年开源。Docker 的商业化也带来了一定的变化。为了更好的进行商业运作,Docker Inc. 将 Docker 开源项目的名称修改为了 Moby,所以大家要是在 GitHub 上没有搜索到 Docker 不要觉得惊讶,因为它现在的名字是 Moby ( github.com/moby/moby )

随着互联网的极速发展,应用程序的功能越来越丰富,而需要迭代的速度要求也越来越高,为了实现这些目标,应用的开发逐渐趋向服务化甚至微服务化。每个应用程序都有其对应依赖的操作系统或者其他程序,而在将应用程序细分为不同的微服务或者是其他形式的微小应用模块后,解决这种依赖问题会愈发显得棘手。有的应用运行环境特别复杂,搭建过程也极易出错,这都是让开发、测试、运维人员焦头烂额的地方。更多时候,开发者们肯定更愿意将他们宝贵的时间用在实际的开发中,而不是纠缠着应用运行环境的问题上。

 

 Docker 的实现,主要归结于三大技术:命名空间 ( Namespaces ) 、控制组 ( Control Groups ) 和联合文件系统 ( Union File System ) 。

Namespace

命名空间是 Linux 核心在 2.4 版本后逐渐引入的一项用于运行隔离的模块。

相信很多开发者在不同的编程语言中都见过命名空间的概念,在这些编程语言中,命名空间的主要目的就是为了集合相同模块的类,区分不同模块间的同名类。

同样的道理,Linux 内核的命名空间,就是能够将计算机资源进行切割划分,形成各自独立的空间。

 通过 PID Namespace,我们可以造就一个独立的进程运行空间,在其中进程的编号又会从 1 开始。在这个空间中运行的进程,完全感知不到外界系统中的其他进程或是其他进程命名空间中运行的进程

Control Groups

资源控制组 ( 常缩写为 CGroups ) 是 Linux 内核在 2.6 版本后逐渐引入的一项对计算机资源控制的模块。

顾名思义,资源控制组的作用就是控制计算机资源的。与以隔离进程、网络、文件系统等虚拟资源为目的 Namespace 不同,CGroups 主要做的是硬件资源的隔离。

之前我们提到了,虚拟化除了制造出虚拟的环境隔离同一物理平台运行的不同程序之外,另一大作用就是控制硬件资源的分配,CGroups 的使用正是为了这样的目的。

 CGroups 除了资源的隔离,还有资源分配这个关键性的作用。通过 CGroups,我们可以指定任意一个隔离环境对任意资源的占用值或占用率,这对于很多分布式使用场景来说是非常有用的功能。

Union File System

联合文件系统 ( Union File System ) 是一种能够同时挂载不同实际文件或文件夹到同一目录,形成一种联合文件结构的文件系统。联合文件系统本身与虚拟化并无太大的关系,但 Docker 却创新的将其引入到容器实现中,用它解决虚拟环境对文件系统占用过量,实现虚拟环境快速启停等问题。

在 Docker 中,提供了一种对 UnionFS 的改进实现,也就是 AUFS ( Advanced Union File System )。

Docker 的理念

在对 Docker 及其背后的一些技术有了一个初步了解之后,我们还要着重说一下 Docker 本身的一些设计理念。如果说熟悉 Docker 背后的技术能够更好的帮助你正确使用 Docker,那么理解 Docker 的理念将更好的指导你如何搭配 Docker 容器间的关系。

Docker 官方提供的架构图来看看 Docker 对容器结构的设计。

    # Docker的四大对象                                                                                       

在 Docker 体系里,有四个对象 ( Object ) 是我们不得不进行介绍的,因为几乎所有 Docker 以及周边生态的功能,都是围绕着它们所展开的。它们分别是:镜像 ( Image )、容器 ( Container )、网络 ( Network )、数据卷 ( Volume )。

镜像

所谓镜像,可以理解为一个只读的文件包,其中包含了虚拟环境运行最原始文件系统的内容

Docker 的镜像与虚拟机中的镜像还是有一定区别的。首先,之前我们谈到了 Docker 中的一个创新是利用了 AUFS 作为底层文件系统实现,通过这种方式,Docker 实现了一种增量式的镜像结构。

 Docker 的镜像实质上是无法被修改的,因为所有对镜像的修改只会产生新的镜像,而不是更新原有的镜像。

容器

容器 ( Container ) 就更好理解了,在容器技术中,容器就是用来隔离虚拟环境的基础设施,而在 Docker 里,它也被引申为隔离出来的虚拟环境。

如果把镜像理解为编程中的类,那么容器就可以理解为类的实例。镜像内存放的是不可变化的东西,当以它们为基础的容器启动后,容器内也就成为了一个“活”的空间。

用更官方的定义,Docker 的容器应该有三项内容组成:

  • 一个 Docker 镜像
  • 一个程序运行环境
  • 一个指令集合

网络

网络通讯是目前最常用的一种程序间的数据交换方式了。 Docker 中,实现了强大的网络功能,我们不但能够十分轻松的对每个容器的网络进行配置,还能在容器间建立虚拟网络,将数个容器包裹其中,同时与其他网络环境隔离。

数据卷

能够这么简单的实现挂载,主要还是得益于 Docker 底层的 Union File System 技术。在 UnionFS 的加持下,除了能够从宿主操作系统中挂载目录外,还能够建立独立的目录持久存放数据,或者在容器间共享。

在 Docker 中,通过这几种方式进行数据共享或持久化的文件或目录,我们都称为数据卷 ( Volume )。

Docker Engine

Docker 官方将其命名为 Docker Engine,同时定义其为工业级的容器引擎 ( Industry-standard Container Engine )。在 Docker Engine 中,实现了 Docker 技术中最核心的部分,也就是容器引擎这一部分。

docker daemon 和 docker CLI

docker最核心的就是 docker daemondocker CLI

所有我们通常认为的 Docker 所能提供的容器管理、应用编排、镜像分发等功能,都集中在了 docker daemon 中,而我们之前所提到的镜像模块、容器模块、数据卷模块和网络模块也都实现在其中。在操作系统里,docker daemon 通常以服务的形式运行以

便静默的提供这些功能,所以我们也通常称之为 Docker 服务。

docker daemon 管理容器等相关资源的同时,它也向外暴露了一套 RESTful API,我们能够通过这套接口对 docker daemon 进行操作。或者更确切的说,是通过这套 RESTful API 对 docker daemon 中运行的容器和其他资源进行管理。

Docker Engine 的版本

对于 Docker Engine 来说,其主要分为两个系列:

  • 社区版 ( CE, Community Edition )
  • 企业版 ( EE, Enterprise Edition )

Docker 的环境依赖

Docker 的容器隔离依赖于 Linux 内核中的相关支持,所以使用 Docker 首先需要确保安装机器的 Linux kernel 中包含 Docker 所需要使用的特性。

 Linux 系统中安装 Docker

因为 Docker 本身就基于 Linux 的核心能力,同时目前主流的 Linux 系统中所拥有的软件包管理程序,已经可以很轻松的帮助我们处理各种依赖问题,所以在 Linux 中安装 Docker 并非什么难事。

# 安装前建议关闭selinux和firewalld

# 关闭防火墙
systemctl stop firewalld
systemctl disable firewalld

# 关闭selinux
sed -i 's/enforcing/disabled/' /etc/selinux/config  # 永久
setenforce 0  # 临时

# 安装依赖包

yum install -y yum-utils

# 添加Docker软件包源

yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

# 安装Docker CE

yum install -y docker-ce

# 启动Docker服务并设置开机启动

systemctl start docker

systemctl enable docker

https://docs.docker.com/engine/install/centos/

官方文档:https://docs.docker.com

阿里云源:http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

配置国内镜像源

在很多编程语言中,为了更好的向大家提供依赖包的管理,通常都会有一些组织研发相应的包管理工具,例如 Java 的 Maven,PHP 的 Composer,Node.js 的 NPM 等等。而这些管理工具背后,也对应着一个默认的依赖包仓库。

 vim /etc/docker/daemon.json

{
    "registry-mirrors": [
        "https://registry.docker-cn.com"
    ]
}

 $ sudo systemctl restart docker

深入镜像实现

Docker 将镜像管理纳入到了自身设计之中,也就是说,所有的 Docker 镜像都是按照 Docker 所设定的逻辑打包的,也是受到 Docker Engine 所控制的。

Docker 的镜像必须通过 Docker 来打包,也必须通过 Docker 下载或导入后使用,不能单独直接恢复成容器中的文件系统。

可以很轻松的在不同的服务器间传递 Docker 镜像,配合 Docker 自身对镜像的管理功能,在不同的机器中传递和共享 Docker 变得非常方便。

对于每一个记录文件系统修改的镜像层来说,Docker 都会根据它们的信息生成了一个 Hash 码,这是一个 64 长度的字符串,足以保证全球唯一性

由于镜像层都有唯一的编码,我们就能够区分不同的镜像层并能保证它们的内容与编码是一致的,这带来了另一项好处,就是允许我们在镜像之间共享镜像层。

查看镜像

镜像是由 Docker 进行管理的,所以它们的存储位置和存储方式等我们并不需要过多的关心,我们只需要利用 Docker 所提供的一些接口或命令对它们进行控制即可。

如果要查看当前连接的 docker daemon 中存放和管理了哪些镜像。

[root@docker ~]# docker image ls

[root@docker ~]# docker images

镜像命名

镜像层的 ID 既可以识别每个镜像层,也可以用来直接识别镜像 ( 因为根据最上层镜像能够找出所有依赖的下层镜像,所以最上层进行的镜像层 ID 就能表示镜像的 ID ),但是使用这种无意义的超长哈希码显然是违背人性的,所以这里我们还要介绍镜像的命名,通过镜像名我们能够更容易的识别镜像。

docker images 命令打印出的内容中,我们还能看到两个与镜像命名有关的数据:REPOSITORYTAG,这两者其实就组成了 docker 对镜像的命名规则。

 镜像的命名我们可以分成三个部分:usernamerepositorytag

  • username: 主要用于识别上传镜像的不同用户,与 GitHub 中的用户空间类似。
  • repository:主要用于识别进行的内容,形成对镜像的表意描述。
  • tag:主要用户表示镜像的版本,方便区分进行内容的不同细节

容器的生命周期

要熟悉 Docker 容器,还有一个重要的概念,也就是容器的生命周期。

容器运行的状态流转图:

 图中色块表示的:CreatedRunningPausedStoppedDeleted

获取镜像

获取现有镜像的方式还是直接从镜像仓库中拉取,因为这种方式简单、快速、有保障。使用命令如下:

[root@docker ~]# docker pull 192.168.178.160/library/php:v1

[root@docker ~]# docker pull ubuntu

Docker Hub

镜像仓库,就不得不提 Docker Hub 了。Docker Hub 是 Docker 官方建立的中央镜像仓库,除了普通镜像仓库的功能外,它内部还有更加细致的权限管理,支持构建钩子和自动构建,并且有一套精致的 Web 操作页面。

Docker Hub 的地址是:hub.docker.com/

Docker Hub 的搜索结果中,有几项关键的信息有助于我们选择合适的镜像:

  • OFFICIAL 代表镜像为 Docker 官方提供和维护,相对来说稳定性和安全性较高
  • STARS 代表镜像的关注人数,这类似 GitHub 的 Stars,可以理解为热度
  • PULLS 代表镜像被拉取的次数,基本上能够表示镜像被使用的频度

容器的创建和启动

Docker 容器的生命周期里分为五种状态,其分别代表着:

  • Created:容器已经被创建,容器所需的相关资源已经准备就绪,但容器中的程序还未处于运行状态。
  • Running:容器正在运行,也就是容器中的应用正在运行。
  • Paused:容器已暂停,表示容器中的所有程序都处于暂停 ( 不是停止 ) 状态。
  • Stopped:容器处于停止状态,占用的资源和沙盒环境都依然存在,只是容器中的应用程序均已停止。
  • Deleted:容器已删除,相关占用的资源及存储在 Docker 中的管理信息也都已释放和移除。

      # Docker常用的管理命令                                                             

       # 容器创建常用选项                                                                                  

      # 容器的常用管理命令                                                                               

      # 容器数据持久化                                                                                

Docker提供2种方式将数据从宿主机上挂载到容器中:

  1. volumes: Docker管理宿主机文件系统的一部分(/var/lib/docker/volumes)
  2. bin mounts: 将宿主机上的任意位置的文件或目录挂载到容器中

volumes的示例:(docker volume create 的方式 )                                                                         

  1. 创建数据卷
    [root@k8s-node2 ~]# docker volume create nginx-vol
    nginx-vol
    [root@k8s-node2 ~]# docker volume ls
    DRIVER    VOLUME NAME
    local     nginx-vol
    [root@k8s-node2 ~]# docker volume inspect nginx-vol
    [
        {
            "CreatedAt": "2021-08-31T15:00:26+08:00",
            "Driver": "local",
            "Labels": {},
            "Mountpoint": "/var/lib/docker/volumes/nginx-vol/_data",
            "Name": "nginx-vol",
            "Options": {},
            "Scope": "local"
        }
    ]
    [root@docker ~]# cd /var/lib/docker/volumes
    [root@docker volumes]# ls
    b42714f6cbc27c9293dde59f940e262906f59d6c7156984b105bf048a356d399  metadata.db
    backingFsBlockDev                                                 nginx-vol
    e189f4d38088845d41d5fde7f246cd03677f29d9b9c679ab806c22bc46ac8ed6
    [root@docker volumes]# cd nginx-vol
    [root@docker _data]# pwd
    [root@docker _data]# pwd
    /var/lib/docker/volumes/nginx-vol/_data (用docker volumes create 创建的的volume的目录)

  2. 使用数据卷的两种挂载方法:

    [root@docker ~]# docker run -d --name=t1 --mount src=nginx-vol,dst=/usr/share/nginx/html -p 88:80 nginx

[root@docker ~]# docker run -d --name=t1 -v nginx-vol:/usr/share/nginx/html -p 88:80 nginx

       bind mounts的示例:(最常用的一种方式)                                                                           

  1. 在宿主机上创建一个挂载的目录:

        

[root@docker ~]# mkdir /opt/wwwroot

      2、把这个目录挂载到容器中去

[root@docker ~]# docker run -d --name web -p 88:80 -v /opt/wwwroot:/usr/share/nginx/html nginx
[root@docker ~]# docker run -d --name web -p 88:80 -v /opt/wwwroot:/usr/share/nginx/html nginx
7425ce44b5e4caab11a737fb06df15c705f463b92785793315e49bcc26e04ec3
[root@docker ~]# cd /opt/wwwroot

 

      # Docker 网络配置                                                              

Dokcer 通过使用 Linux 桥接提供容器之间的通信,docker0 桥接接口的目的就是方便 Docker 管理。当 Docker daemon 启动时需要做以下操作:

  • creates the docker0 bridge if not present
    • # 如果 docker0 不存在则创建
  • searches for an IP address range which doesn’t overlap with an existing route
    • # 搜索一个与当前路由不冲突的 ip 段
  • picks an IP in the selected range
    • # 在确定的范围中选择 ip
  • assigns this IP to the docker0 bridge
    • # 绑定 ip 到 docker0

      Docker 四种网络模式                                                   

      四种网络模式摘自  Docker 网络详解及 pipework 源码解读与实践

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

      • host 模式,使用 --net=host 指定。
      • container 模式,使用 --net=container:NAMEorID 指定。
      • none 模式,使用 --net=none 指定。
      • bridge 模式,使用 --net=bridge 指定,默认设置。
        • host 模式                                         

          如果启动容器的时候使用 host 模式,那么这个容器将不会获得一个独立的 Network Namespace,而是和宿主机共用一个 Network Namespace。容器将不会虚拟出自己的网卡,配置自己的 IP 等,而是使用宿主机的 IP 和端口。

          例如,我们在 10.10.101.105/24 的机器上用 host 模式启动一个含有 web 应用的 Docker 容器,监听 tcp 80 端口。当我们在容器中执行任何类似 ifconfig 命令查看网络环境时,看到的都是宿主机上的信息。而外界访问容器中的应用,则直接使用 10.10.101.105:80 即可,不用任何 NAT 转换,就如直接跑在宿主机中一样。但是,容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。

          container 模式                                  

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

          none模式                                           

          这个模式和前两个不同。在这种模式下,Docker 容器拥有自己的 Network Namespace,但是,并不为 Docker容器进行任何网络配置。也就是说,这个 Docker 容器没有网卡、IP、路由等信息。需要我们自己为 Docker 容器添加网卡、配置 IP 等。

      •         bridge模式                                        

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

      列出当前主机网桥                          

      [root@k8s-master ~]# brctl show
      bridge name bridge id       STP enabled interfaces
      docker0     8000.0242588ed474   no     
      virbr0      8000.52540032c54e   yes     virbr0-nic
      

       查看当前 docker0 ip                      

      [root@k8s-master ~]# ifconfig docker0
      docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
              inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
              ether 02:42:58:8e:d4:74  txqueuelen 0  (Ethernet)
              RX packets 0  bytes 0 (0.0 B)
              RX errors 0  dropped 0  overruns 0  frame 0
              TX packets 0  bytes 0 (0.0 B)
              TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
      

       Docker 使用IPtables实现网络通信            

       外部访问容器的流程:--------------->      

      [root@docker ~]# iptables -t nat -vnL DOCKER
      Chain DOCKER (2 references)
       pkts bytes target     prot opt in     out     source               destination         
          0     0 RETURN     all  --  docker0 *       0.0.0.0/0            0.0.0.0/0           
          1    52 DNAT       tcp  --  !docker0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:88 to:172.17.0.2:80
      
      52 DNAT       tcp  --  !docker0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:88 to:172.17.0.2:80 (容器的目的地址)
      通过DNAT(目标网络地址转换) 的转换,把宿主机上的88端口流量转换到容器地址的80端口上
      [root@docker ~]# ip route
      default via 192.168.178.2 dev ens33 proto static metric 100 
      172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 
      192.168.122.0/24 dev virbr0 proto kernel scope link src 192.168.122.1 
      192.168.178.0/24 dev ens33 proto kernel scope link src 192.168.178.160 metric 100 
      

      DNAT的数据流量就直接放在docker0这个二层的交换机上,进行RAP广播,让容器是172.17.0.2的地址收到

       容器访问外部的流程:-------->                   

      [root@docker ~]# iptables -t nat -vnL POSTROUTING
      Chain POSTROUTING (policy ACCEPT 33 packets, 2484 bytes)
       pkts bytes target     prot opt in     out     source               destination         
          0     0 MASQUERADE  all  --  *      !docker0  172.17.0.0/16        0.0.0.0/0           
          2   181 RETURN     all  --  *      *       192.168.122.0/24     224.0.0.0/24        
          0     0 RETURN     all  --  *      *       192.168.122.0/24     255.255.255.255     
          0     0 MASQUERADE  tcp  --  *      *       192.168.122.0/24    !192.168.122.0/24     masq ports: 1024-65535
          0     0 MASQUERADE  udp  --  *      *       192.168.122.0/24    !192.168.122.0/24     masq ports: 1024-65535
          0     0 MASQUERADE  all  --  *      *       192.168.122.0/24    !192.168.122.0/24    
        174 13059 POSTROUTING_direct  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
        174 13059 POSTROUTING_ZONES_SOURCE  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
        174 13059 POSTROUTING_ZONES  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
          0     0 MASQUERADE  tcp  --  *      *       172.17.0.2           172.17.0.2           tcp dpt:80
      

       通查看88端口的数据监听:

      [root@docker ~]# ss -antp |grep 88
      [root@docker ~]# ss -antp |grep 88
      LISTEN     0      128          *:88                       *:*                   users:(("docker-proxy",pid=4220,fd=4))
      LISTEN     0      128       [::]:88                    [::]:*                   users:(("docker-proxy",pid=4228,fd=4))
      

      先拉起一个busybox的工具容器:

      [root@docker ~]# docker run -itd busybox

      进入这个busybox容器中:

      [root@docker ~]# docker exec -it 1938aaf5c003 sh
      / #
      / # ifconfig

      eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:03  
                inet addr:172.17.0.3  Bcast:172.17.255.255  Mask:255.255.0.0
                UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
                RX packets:8 errors:0 dropped:0 overruns:0 frame:0
                TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
                collisions:0 txqueuelen:0 
                RX bytes:656 (656.0 B)  TX bytes:0 (0.0 B)
      
      lo        Link encap:Local Loopback  
                inet addr:127.0.0.1  Mask:255.0.0.0
                UP LOOPBACK RUNNING  MTU:65536  Metric:1
                RX packets:0 errors:0 dropped:0 overruns:0 frame:0
                TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
                collisions:0 txqueuelen:1000 
                RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
      

      / # ping baidu.com是可以ping得出去的

      PING baidu.com (220.181.38.148): 56 data bytes
      64 bytes from 220.181.38.148: seq=0 ttl=127 time=53.152 ms
      64 bytes from 220.181.38.148: seq=1 ttl=127 time=52.830 ms
      

       查看本地路由表:

       / # ip route
      default via 172.17.0.1 dev eth0
      172.17.0.0/16 dev eth0 scope link  src 172.17.0.3

      宿主机的路由表:

      [root@docker ~]# ip route
      default via 192.168.178.2 dev ens33 proto static metric 100
      172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1
      192.168.122.0/24 dev virbr0 proto kernel scope link src 192.168.122.1
      192.168.178.0/24 dev ens33 proto kernel scope link src 192.168.178.160 metric 100

      SANT :源地址数据转换 MASQUERADE的封装:然后通过宿主机的路由转发到公网上。

        # Dockerfile  构建镜像                                                                                  

       Docker通过Dockerfile自动构建镜像,Dockerfile是一个包含用于组建镜像的文本文件,由一条一条的指令组成。

      FROM centos:latest   
      RUN yum install gcc -y
      COPY run.sh /usr/bin
      EXPOSE 80
      CMD [“run.sh”]
      
      指令 描述
      FROM 构建新镜像是基于哪个镜像
      LABE 标签
      RUN 构建镜像时运行的Shell命令
      COPY 拷贝文件或目录到镜像中
      ADD 解压压缩包并拷贝
      ENV 设置环境变量
      USER 为RUN、CMD和ENTRYPOINT执行命令指定运行用户
      EXPOSE 声明容器运行的服务端口
      WORKDIR 为RUN、CMD、ENTRYPOINT、COPY和ADD设置工作目录
      CMD 运行容器时默认执行,如果有多个CMD指令,最后一个生效

          简单实例:                                                                                                                                  

      [root@docker ~]# mkdir /docker_test
      [root@docker ~]# cd /docker_test
      [root@docker docker_test]# vim Dockerfile
      

       编写Dockerfile文件:

      FROM centos:7.8
      RUN yum  install epel-release -y && 
          yum install nginx -y
      CMD ["nginx","g","daemon off;"]

      [root@docker docker_test]# docker build -t nginx:v2 .

      Successfully built f41da4459f1e
      Successfully tagged nginx:v2
      
      [root@docker docker_test]# docker images 
      REPOSITORY                   TAG        IMAGE ID       CREATED          SIZE
      nginx                        v2         f41da4459f1e   40 seconds ago   405MB
      

       实例1:部署一个nginx:1.15.5的Dockerfile                                                                                    
      1、新建一个目录,在目录下放置需要到的nginx的安装文件。和nginx的配置文件。

      [root@docker nginx]# ls
      Dockerfile  nginx-1.15.5.tar.gz  nginx.conf  php.conf

      2、编辑nginx.conf文件

      [root@docker nginx]# cat nginx.conf
      user                 nobody;
      worker_processes     4;
      worker_rlimit_nofile 65535;
      
      error_log  logs/error.log  notice;
      
      pid        /var/run/nginx.pid;
      
      events {
          use epoll;
          worker_connections  4096;
      }
      
      http {
      
          include       mime.types;
          default_type  application/octet-stream;
      
          log_format  main '$remote_addr - $remote_user [$time_local] "$request" '
                            '$status $body_bytes_sent "$http_referer" '
                            '"$http_user_agent" "$http_x_forwarded_for"';
      
          access_log off;
          keepalive_timeout  65;
      
          client_max_body_size         64m;
          include /usr/local/nginx/conf/vhost/*.conf;
          
          server {
              listen 80;
              server_name localhost;
              index index.html;
      
              location / {
                  root html;
              }
          }
      
      }
      

       3、编辑用到的php.conf文件

      server {
          listen 80;
          server_name example.ctnrs.com;
          index index.php index.html;
      
          access_log logs/www.ctnrs.com_access.log;
          error_log logs/www.ctnrs.com_error.log;
      
          location / {
              root /wwwroot;
          }
      
          location ~* .php$ {
              root /wwwroot;
              fastcgi_pass lnmp_php:9000;
              fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
              include fastcgi_params;
          }
      }
      

       4、编辑Dockerfile文件

      FROM centos:7
      LABEL maintainer www.yuanye.com
      RUN yum install -y gcc gcc-c++ make 
          openssl-devel pcre-devel gd-devel 
          iproute net-tools telnet wget curl && 
          yum clean all && 
          rm -rf /var/cache/yum/*
      
      ADD nginx-1.15.5.tar.gz /
      RUN cd nginx-1.15.5 && 
          ./configure --prefix=/usr/local/nginx 
          --with-http_ssl_module 
          --with-http_stub_status_module && 
          make -j 4 && make install && 
          mkdir /usr/local/nginx/conf/vhost && 
          cd / && rm -rf nginx* && 
          ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
      
      ENV PATH $PATH:/usr/local/nginx/sbin
      COPY nginx.conf /usr/local/nginx/conf/nginx.conf
      WORKDIR /usr/local/nginx
      EXPOSE 80
      CMD ["nginx", "-g", "daemon off;"]
      

      5、构建新的nginx镜像

      [root@docker nginx]# docker build -t nginx:v1 .

      Successfully built a3818c705c73
      Successfully tagged nginx:v1
      6、查看构建好的新镜像nginx:v1

       7、通过新镜像部署容器和访问

      [root@docker wwwroot]# docker run -d --name=web-t2 -v nginx-vol:/usr/local/nginx/html -p 92:80 nginx:v1

      8、在浏览器中检查

        实例2:部署一个tomcat的Dockerfile                                                                                       

       1、新建一个文件夹mkdir

      [root@docker tomcat]# ll
      total 27336
      -rw-r--r--. 1 root root  9717059 Jul  5  2019 apache-tomcat-8.5.43.tar.gz
      -rw-r--r--. 1 root root      575 Jun 20  2020 Dockerfile
      -rw-r--r--. 1 root root 18265402 Jun 20  2020 ROOT.war
      2、编辑Tomcat文件Dockerfile

      FROM centos:7
      MAINTAINER www.yuanye.com
      
      ENV VERSION=8.5.43
      
      RUN yum install java-1.8.0-openjdk wget curl unzip iproute net-tools -y && 
          yum clean all && 
          rm -rf /var/cache/yum/*
      
      ADD apache-tomcat-${VERSION}.tar.gz /usr/local/
      RUN mv /usr/local/apache-tomcat-${VERSION} /usr/local/tomcat && 
          sed -i '1a JAVA_OPTS="-Djava.security.egd=file:/dev/./urandom"' /usr/local/tomcat/bin/catalina.sh && 
          ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
      
      ENV PATH $PATH:/usr/local/tomcat/bin
      
      WORKDIR /usr/local/tomcat
      
      EXPOSE 8080
      CMD ["catalina.sh", "run"]
      

       3、构建新的Tomcat镜像

      [root@docker tomcat]# docker build -t tomcat:v1 .
      Successfully built 1d536d55624c
      Successfully tagged tomcat:v1
      4、用新建的Tomcat镜像构建容器
      [root@docker tomcat]# docker run -d --name=tom1 -p 9090:8080 tomcat:v1

      5、在宿主机上检查新容器的运行情况

      实例3:部署一个PHP的Dockerfile                                                                                         

      1、新建一个PHP的Dockerfile目录

      [root@docker dockerfile]# cd php
      [root@docker php]# ll
      total 18952
      -rw-r--r--. 1 root root     1254 Jun 20  2020 Dockerfile
      -rw-r--r--. 1 root root 19300905 Apr 26  2018 php-5.6.36.tar.gz
      -rw-r--r--. 1 root root    23104 Oct 29  2018 php-fpm.conf
      -rw-r--r--. 1 root root    73696 Nov  3  2018 php.ini
      2、编辑PHP的dockerfile文件

      FROM centos:7
      MAINTAINER www.yuanye.com
      RUN yum install epel-release -y && 
          yum install -y gcc gcc-c++ make gd-devel libxml2-devel 
          libcurl-devel libjpeg-devel libpng-devel openssl-devel 
          libmcrypt-devel libxslt-devel libtidy-devel autoconf 
          iproute net-tools telnet wget curl && 
          yum clean all && 
          rm -rf /var/cache/yum/*
      
      ADD php-5.6.36.tar.gz /
      RUN cd php-5.6.36 && 
          ./configure --prefix=/usr/local/php 
          --with-config-file-path=/usr/local/php/etc 
          --enable-fpm --enable-opcache 
          --with-mysql --with-mysqli --with-pdo-mysql 
          --with-openssl --with-zlib --with-curl --with-gd 
          --with-jpeg-dir --with-png-dir --with-freetype-dir 
          --enable-mbstring --with-mcrypt --enable-hash && 
          make -j 4 && make install && 
          cp php.ini-production /usr/local/php/etc/php.ini && 
          cp sapi/fpm/php-fpm.conf /usr/local/php/etc/php-fpm.conf && 
          sed -i "90a daemonize = no" /usr/local/php/etc/php-fpm.conf && 
          mkdir /usr/local/php/log && 
          cd / && rm -rf php* && 
          ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
      
      ENV PATH $PATH:/usr/local/php/sbin
      COPY php.ini /usr/local/php/etc/
      COPY php-fpm.conf /usr/local/php/etc/
      WORKDIR /usr/local/php
      EXPOSE 9000
      CMD ["php-fpm"]
      

       3、构建一个新的php镜像

      [root@docker php]# docker build -t php:v1 .

      Successfully built 0ae7226f33ff
      Successfully tagged php:v1
      4、查看构建好的新镜像

      [root@docker php]# docker image ls
      REPOSITORY                   TAG        IMAGE ID       CREATED          SIZE
      php                          v1         0ae7226f33ff   44 seconds ago   629MB
      5、用新的镜像构建容器

      [root@docker php]# docker run -d --name=php-1 -p 9002:9000 php:v1
      实例4:部署一个java的Dockerfile                                                                              

      1、新建java的目录

      [root@docker dockerfile]# cd java
      [root@docker java]# ll
      total 8
      -rw-r--r--. 1 root root 384 Jun 20  2020 Dockerfile
      -rw-r--r--. 1 root root 960 Jun 20  2020 hello.jar
      2、编辑java的Dockerfile文件

      FROM java:8-jdk-alpine
      LABEL maintainer www.ctnrs.com
      ENV JAVA_OPTS="$JAVA_OPTS -Dfile.encoding=UTF8 -Duser.timezone=GMT+08"
      RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && 
          apk add -U tzdata && 
          ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
      COPY hello.jar /
      EXPOSE 8888
      CMD ["/bin/sh", "-c", "java -jar $JAVA_OPTS /hello.jar"]
      

       3、构建java的新镜像

      [root@docker java]# docker build -t java:v1 .

      Successfully built 9d1b62aea028
      Successfully tagged java:v1
      4、查看新建的java镜像

      [root@docker java]# docker images
      REPOSITORY                   TAG            IMAGE ID       CREATED          SIZE
      java                         v1             9d1b62aea028   32 seconds ago   147MB

      5、用新的java:v1镜像新建一个容器

      [root@docker java]# docker run -d --name=java-t1 -p 9003:8888 java:v1

      构建镜像的命令列表:                                                                                                                    

      Usage: docker build [OPTIONS] PATH | URL | -[flags]

      Options:

      -t, --tag list                   # 镜像名称

      -f, --file string               # 指定Dockerfile文件位置

      # docker build -t shykes/myapp .

      # docker build -t shykes/myapp -f /path/Dockerfile /path

      # docker build -t shykes/myapp http://www.example.com/Dockerfile   #dockerfile文件来源为网上

          # Harbor镜像仓库搭建与使用                                                                               

        Harbor是由VMWare公司开源的容器镜像仓库。事实上,Harbor是在Docker Registry上进行了相应的企业级扩展,从而获得了更加广泛的应用,这些新的企业级特性包括:管理用户界面,基于角色的访问控制,AD/LDAP集成以及审计日志等,足以满足基本企业需求。
      它包括权限管理(RBAC)、LDAP、日志审核、管理界面、自我注册、镜像复制和中文支持等功能。

      Harbor的所有服务组件都是在Docker中部署的,所以官方安装使用Docker-compose快速部署,所以需要安装Docker、Docker-compose。由于Harbor是基于Docker Registry V2版本,所以就要求Docker版本不小于1.10.0,Docker-compose版本不小于1.6.0
      ————————————————
      官方:https://goharbor.io/

      Github:https://github.com/goharbor/harbor

      软件:

      •Docker CE 17.06版本

      •Docker Compose1.18版本

      Harbor安装有2种方式:

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

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

      1、准备安装Docker和Docker Compose

      在这个网址上下载docker compose:

      https://github.com/docker/compose/releases

      上传到系统中,然后把docker-compose的文件移动到/usr/bin/docker-compose目录下运行

      [root@docker ~]# mv docker-compose-Linux-x86_64 /usr/bin/docker-compose
      然后给这个文件加一个可执行权限

      [root@docker ~]# chmod +x /usr/bin/docker-compose

      执行docker-compose就会出现帮助了

       2、解压Harbor的文件

      [root@docker ~]# tar zxvf harbor-offline-installer-v2.3.2.tgz
       

      3、编辑Harbor的配置文件harbor.yml

      hostname: 192.168.178.160
      
      # http related config
      http:
        # port for http, default is 80. If https enabled, this port will redirect to https port
        port: 80
      
      # https related config
      

       

       4、安装

      初始化配置文件和pull取到prepare的镜像

      [root@docker harbor]# ./prepare

      安装harbor系统
      [root@docker harbor]# ./install.sh

       

       

       执行[root@docker harbor]# docker-compose ps查看镜像的情况

       5、通过宿主机上的浏览器访问http://192.168.178.160:80 harbor的主页面

      用户名:admin   ps:Harbor12345

       6、推送镜像到Harbor仓库中

      因为是用HTTP访问的模式,所以需要在docker中配置可信任:

      [root@docker ~]# cd /etc/docker

      [root@docker docker]# vim daemon.json

      {
        "registry-mirrors": ["https://m9s0cjt1.mirror.aliyuncs.com"],
         "insecure-registries":["192.168.178.160"]
      }
      

       [root@docker docker]# systemctl restart docker

       给镜像打tag的

      [root@docker ~]# docker tag tomcat:v1 192.168.178.160/library/tomcat:v1

       

      [root@docker harbor]# docker-compose up -d 把harbor的镜像全部启动

       登录到Harbor上进行push

      [root@docker harbor]# docker login 192.168.178.160
      Username: admin
      Password:

      [root@docker harbor]# docker push 192.168.178.160/library/tomcat:v1 

      Harbor的基本操作命令:                                                                         

       1、配置http镜像仓库可信任

      # vi /etc/docker/daemon.json

      {     "insecure-registries":["reg.ctnrs.com"]

      }

      # systemctl restart docker

      2、打标签

      # docker tag centos:7 reg.ctnrs.com/library/centos:7

      3、上传

      # docker push reg.ctnrs.com/library/centos:7

      4、下载

      # docker pull reg.ctnrs.com/library/centos:7

                                                  yuanye 2021.9.1                           

原文地址:https://www.cnblogs.com/yyuuee/p/15210773.html