Java运维-Docker

容器

容器的概念

  1. 容器的概念在软件行业应用很广,比如 Tomcat 容器,Java 开发所使用的 Spring 容器。而今天介绍的容器,是基于操作系统特性所实现的容器化技术。它与 Tomcat 类似,也是用于存放应用的容器。区别在于 Tomcat 仅仅用于存放 Servlet 应用,而基于操作系统所实现的容器化技术所构建的容器,可以存放几乎所有应用。
  2. 容器是利用操作系统(Linux)的容器化技术(操作系统自带的命令或者API)所构建的一套应用运行时期的独立的标准化环境,在这套环境中集成了要运行的软件所依赖的所有其他应用、工具等,容器内的一切工具、应用是以为容器中的主应用运行而生的。

容器化的两大特性

  1. 标准化: 一个应用运行时期所需要的所有本地环境信息(工具、依赖等)都将集成在一个容器中,因此任意一台服务器只要支持容器化技术,都能够轻易的将一个应用直接部署起来。
  2. 隔离性: 容器中的环境信息与其他容器,甚至是宿主机之间都是隔离的。这个隔离包括了网络、文件系统、内存、硬盘和CPU等等关键硬件资源。我们可以在一台机器上部署多个容器,而多个容器中分别运行着不同版本 JDK 的 Java 应用,它们之间不会存在任何冲突问题。

容器的作用

  1. 拥有了标准化与隔离性,可以轻松的为需要部署的应用构建一套独立的运行环境,且可以在任意支持容器运行的环境中快速部署我们的应用,提高应用的交付能力

容器 VS 虚拟机

  1. 容器是应用程序的抽象,将应用程序代码与环境打包在一起构建一套独立的运行环境,多个容器可以在一台计算机上运行并且与其他容器共享OS内核。且每个容器之间利用用户空间来进行资源隔离,相对于操作系统来说是非常轻量的。
  2. 虚拟机则完全是对于一台计算机的抽象,一个操作系统上可以运行多个虚拟机,但每个虚拟机都是一个独立运行的操作系统,且有着完整的一套基于硬件设备的虚拟设备进行资源的隔离,这样的抽象方式导致虚拟机无论是在运行时的资源损耗还是启动的效率都是非常重量级的操作。

具体对比如下表格:

类别 容器 虚拟机
操作系统 与主机共享 OS 在宿主机OS之上运行虚拟机OS
部署难度 非常简单 组件多,部署复杂
启动速度 秒级 分钟级
执行性能 和物理系统几乎一致 VM会占用一部分资源
镜像体积 容器镜像是 MB 级别的 虚拟机镜像是GB级别的
管理效率 管理简单 组件相互依赖,管理复杂
隔离性 比较弱 彻底隔离

Docker

Docker的概念

  1. Docker 官网
  2. Docker 的思想来源于集装箱,集装箱最大的作用在于能够将货品标准化,并且集装箱与集装箱之间互相隔离,货物之间不会有任何影响。那么就不再需要专门的船去运输专门的货品,只要货品在集装箱内好好封存着,那就可以使用一艘大船将他们都运走。
  3. 对于我们来说,Docker 也担任了类似的角色,应用或者所依赖的第三方服务可以理解为货品,而 Docker 则是将我们的货品规范化管理起来,从而可以轻易的完成产品交付,环境转移等等诸多问题,并且 Docker 对于主机资源的消耗非常小,可以实现对服务器资源的最大利用
  4. Docker(Moby)诞生于2013年,是一款基于 Linux LXC 容器化技术的开源的容器引擎。需要注意的是,2013版原始的开源版本 “Docker” 现在不叫 “Docker” 了,而是 “Moby”。这一改变发生在 2017 年的 Docker Con 大会上,因此现在常说的 “Docker” 实际上代表的是 Docker 公司,现在市面上所能看到的 Docker 版本通常为 Docker EE(企业版)和 Docker CE(社区版),也就是收费版和免费版本的区别,而现在的 Docker CE 实际上就可以理解为 “Moby”。企业版有一些丰富的功能,收费,所以现在使用k8s。
  5. Docker是一个将操作系统的容器化技术封装后的容器引擎,核心功能是构建、打包和运行单个容器,不是容器。
  6. 作用:将应用及其依赖(代码、库、环境配置等)打包成标准化、轻量级的容器镜像。

Docker 三大概念:镜像、容器、仓库

  1. 镜像(Image):可以理解为一个只读的压缩包文件(可以类比于操作系统的ISO镜像),其中包含了容器运行时的所有依赖包。镜像可以用来构建容器,一个镜像可以创建多个容器
  2. 容器(Container): 容器是由镜像构建出的实例(可以理解为一个运行时的空间)。它可以被启动、停止、运行、删除。每个容器之间是互相隔离的、保证安全的独立空间
  3. 仓库(Repository):仓库是用于存放镜像的地方,类似于 Maven 仓库、Git 仓库等用途。仓库之上还有 仓库注册服务器(Registry) 的概念,上面可以存放着多个仓库,每个仓库中又有多个镜像,而每个镜像又可以有多个标签(tag)。目前Docker 官方的公开仓库是 Docker Hub,我们可以使用类似 Git 命令的方式去 pull/push 镜像。
    1. 如果需要构建容器,先从仓库拉取镜像,然后构建容器。

图

Docker的安装(CenterOS环境)

  1. 简介:Docker CE 是免费的 Docker 产品的新名称,Docker CE 包含了完整的 Docker 平台,非常适合开发人员和运维团队构建容器 APP。
  2. Docker CE 镜像:[来源] 阿里云镜像站
  3. 配置方法(CentOS 7(使用 yum 进行安装))

     # step 1: 安装必要的一些系统工具
     sudo yum install -y yum-utils device-mapper-persistent-data lvm2
        
     # Step 2: 添加软件源信息,更换镜像仓库地址为阿里
     sudo yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
     # PS:如果出现如下错误信息
     Loaded plugins: fastestmirror
     adding repo from: https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
     grabbing file https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo to /etc/yum.repos.d/docker-ce.repo
     Could not fetch/save url https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo to file /etc/yum.repos.d/docker-ce.repo: [Errno 14] curl#60 - "Peer's Certificate issuer is not recognized."
     # 编辑 /etc/yum.conf 文件, 在 [main] 下面添加 sslverify=0 参数
     vi /etc/yum.conf
     # 配置如下----------------------
     [main]
     sslverify=0
     # -----------------------------
        
     # Step 3: 更新并安装Docker-CE
     sudo yum makecache fast
     sudo yum -y install docker-ce
        
     # Step 4: 开启Docker服务
     sudo service docker start
        
     # Step 5: 安装校验
     docker version
        
     # 控制台输出日志
     Client:
      Version:      17.03.0-ce
      API version:  1.26
      Go version:   go1.7.5
      Git commit:   3a232c8
      Built:        Tue Feb 28 07:52:04 2017
      OS/Arch:      linux/amd64
        
     Server:
      Version:      17.03.0-ce
      API version:  1.26 (minimum version 1.12)
      Go version:   go1.7.5
      Git commit:   3a232c8
      Built:        Tue Feb 28 07:52:04 2017
      OS/Arch:      linux/amd64
      Experimental: false
        
     # 注意:
     # 官方软件源默认启用了最新的软件,您可以通过编辑软件源的方式获取各个版本的软件包。例如官方并没有将测试版本的软件源置为可用,您可以通过以下方式开启。同理可以开启各种测试版本等。
     # vim /etc/yum.repos.d/docker-ee.repo
     #   将[docker-ce-test]下方的enabled=0修改为enabled=1
     #
     # 安装指定版本的Docker-CE:
     # Step 1: 查找Docker-CE的版本:
     # yum list docker-ce.x86_64 --showduplicates | sort -r
     #   Loading mirror speeds from cached hostfile
     #   Loaded plugins: branch, fastestmirror, langpacks
     #   docker-ce.x86_64            17.03.1.ce-1.el7.centos            docker-ce-stable
     #   docker-ce.x86_64            17.03.1.ce-1.el7.centos            @docker-ce-stable
     #   docker-ce.x86_64            17.03.0.ce-1.el7.centos            docker-ce-stable
     #   Available Packages
     # Step2: 安装指定版本的Docker-CE: (VERSION例如上面的17.03.0.ce.1-1.el7.centos)
     # sudo yum -y install docker-ce-[VERSION]
    

Docker 加速

  1. 由于 Docker 默认下载镜像的仓库是在国外的(Docker Hub), 因此国内用户访问相对来说会较慢一些, 目前国内一些大公司与学校搭建了一些国内的镜像仓库, 可以让我们在下载镜像时更方便些
  2. 阿里云镜像仓库配置
    1. 注册阿里云账号,并登陆到阿里云后台,进入控制台面板
    2. 进入控制台以后,找到左上方的三横的功能列表按钮,在弹出来的功能列表处选择弹性计算下的容器镜像服务
    3. 进入容器镜像服务页面后,点击左侧菜单栏中镜像中心下的镜像加速器菜单获取镜像加速器地址,在操作文档处选择 Docker 所在服务器的操作系统,并按照文档提示完成配置即可
  3. CentOS环境下如何修改仓库地址
    1. 针对Docker客户端版本大于 1.10.0 的用户,您可以通过修改daemon配置文件/etc/docker/daemon.json来使用加速器
     sudo mkdir -p /etc/docker
     sudo tee /etc/docker/daemon.json <<-'EOF'
     {
       "registry-mirrors": ["此处修改成你自己的加速 url"]
     }
     EOF
     sudo systemctl daemon-reload
     sudo systemctl restart docker
    

常用命令

图

  1. 图中一共有6个对象:Images、Container、Host(主机)、Tarfiles、Dockerfile、Registry、Engine
  2. 主要是体现了Images(镜像)与其他对象之间的操作,比如将1个镜像运行为一个容器,使用run命令

镜像相关

# 从远程仓库查找镜像,若没有配置国内服务,默认从Docker Hub查询
docker search xxx
# 拉取镜像,通过 镜像名称:Tag  的方式定位镜像,其中 Tag 你可以理解为版本号 `docker pull <imageName:tag>
docker pull centos:7
# 查看本地镜像,命令来查看本地已有的镜像
docker images xxx
# 删除镜像
docker rmi centos:7

容器相关

docker run 创建且运行一个容器

  1. 直接通过 docker run 命令创建并运行一个容器,如果该容器的镜像在本地存在那么则直接使用本地的镜像,如果不存在那么就会从远程仓库中下载镜像,并在下载完成后将该容器创建并运行起来
  2. 举例:docker run hello-world
  3. 直接通过 docker run 镜像名:tag 可以快速运行一个容器,不过并不是所有容器都会长时间的保持着持续运行,例如上面的 hello-world 容器就仅仅只是简单的输出一段内容后既自动退出。
  4. docker run 命令提供了许多的可选参数,你可以通过这些参数来实现对容器进行更深层的控制,以下是关于 docker run 命令的详细使用方式以及相关参数说明
Usage:	docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

Run a command in a new container

Options:
      --add-host list                  添加一个自定义的 主机名-ip 的映射 (host:ip)
  -a, --attach list                   Attach to STDIN, STDOUT or STDERR
      --blkio-weight uint16            Block IO (relative weight), between 10 and 1000, or 0 to disable (default 0)
      --blkio-weight-device list       Block IO weight (relative device weight) (default [])
      --cap-add list                   Add Linux capabilities
      --cap-drop list                  Drop Linux capabilities
      --cgroup-parent string           Optional parent cgroup for the container
      --cidfile string                 将容器id写到一个指定的文件
      --cpu-period int                 限制 CPU 在指定周期内配合下面的配置:单位微秒:100000μs=100ms
      --cpu-quota int                  限制 CPU 可以使用的时间:单位微秒:100000μs=100ms
      --cpu-rt-period int              Limit CPU real-time period in microseconds
      --cpu-rt-runtime int             Limit CPU real-time runtime in microseconds
  -c, --cpu-shares int                 CPU shares (relative weight)
      --cpus decimal                   限制容器可以使用的 CPU 数量
      --cpuset-cpus string             CPUs in which to allow execution (0-3, 0,1)
      --cpuset-mems string             MEMs in which to allow execution (0-3, 0,1)
  -d, --detach                         容器在后台运行且容器启动后打印容器id
      --detach-keys string             Override the key sequence for detaching a container
      --device list                    Add a host device to the container
      --device-cgroup-rule list        Add a rule to the cgroup allowed devices list
      --device-read-bps list           Limit read rate (bytes per second) from a device (default [])
      --device-read-iops list          Limit read rate (IO per second) from a device (default [])
      --device-write-bps list          Limit write rate (bytes per second) to a device (default [])
      --device-write-iops list         Limit write rate (IO per second) to a device (default [])
      --disable-content-trust          Skip image verification (default true)
      --dns list                       自定义 dns 列表
      --dns-option list                Set DNS options
      --dns-search list                Set custom DNS search domains
      --domainname string              Container NIS domain name
      --entrypoint string              Overwrite the default ENTRYPOINT of the image
  -e, --env list                      为容器设置环境变量 name=value,可以设置多个
      --env-file list                  读取一个环境变量文件
      --expose list                    Expose a port or a range of ports
      --gpus gpu-request               GPU devices to add to the container ('all' to pass all GPUs)
      --group-add list                 为容器添加一个组
      --health-cmd string              Command to run to check health
      --health-interval duration       Time between running the check (ms|s|m|h) (default 0s)
      --health-retries int             Consecutive failures needed to report unhealthy
      --health-start-period duration   Start period for the container to initialize before starting health-retries countdown (ms|s|m|h) (default 0s)
      --health-timeout duration        Maximum time to allow one check to run (ms|s|m|h) (default 0s)
      --help                           Print usage
  -h, --hostname string               设置容器的主机名
      --init                           Run an init inside the container that forwards signals and reaps processes
  -i, --interactive                   以交互模式运行容器,通常与 -t 同时使用
      --ip string                      设置容器的 IPv4 地址 (e.g., 172.30.100.104)
      --ip6 string                     设置容器的 IPv6 地址 (e.g., 2001:db8::33)
      --ipc string                     IPC mode to use
      --isolation string               Container isolation technology
      --kernel-memory bytes            容器中内核的可使用内存数,单位可以为 b,k,m,g。最小为 4M
  -l, --label list                    Set meta data on a container
      --label-file list                Read in a line delimited file of labels
      --link list                      打通当前容器和另一个容器的网络
      --link-local-ip list             Container IPv4/IPv6 link-local addresses
      --log-driver string              Logging driver for the container
      --log-opt list                   Log driver options
      --mac-address string             设置容器 MAC 地址 (e.g., 92:d0:c6:0a:29:33)
  -m, --memory bytes                   内存限制,格式是数字加单位,单位可以为 b,k,m,g。最小为 4M
      --memory-reservation bytes       内存的软性限制。格式同上
      --memory-swap bytes              内存+交换分区大小总限制。格式同上。必须必-m设置的大
      --memory-swappiness int          Tune container memory swappiness (0 to 100) (default -1)
      --mount mount                    加载一个磁盘到容器中
      --name string                    为容器设置一个名字
      --network network                Connect a container to a network
      --network-alias list             Add network-scoped alias for the container
      --no-healthcheck                 Disable any container-specified HEALTHCHECK
      --oom-kill-disable               是否阻止 OOM killer 杀死容器,默认没设置
      --oom-score-adj int              容器被 OOM killer 杀死的优先级,范围是[-1000, 1000],默认为 0
      --pid string                     pid 命名空间,默认没有设置。当前容器只能看到容器内所运行的进程 pid。另外还有两种模式可以设置:'container:<name|id>' 查看某一个容器中的所有进程,'host'表示查看主机的所有进程
      --pids-limit int                 Tune container pids limit (set -1 for unlimited)
      --privileged                     Give extended privileges to this container
  -p, --publish list                   将容器中的某一个端口映射到主机,配置格式为 hostPort:containerPort
  -P, --publish-all                    将容器中所有暴露的端口映射到主机的随机端口上
      --read-only                      Mount the container's root filesystem as read only
      --restart string                 容器退出时的重启策略,默认为 no,可选配置有:no,on-failure,always 其中 on-failure 可以配置重启次数如 on-failure:3 表示当容器因为失败而退出时重启,如果重启超过3次还失败则放弃重启
      --rm                             当容器退出时自动删除
      --runtime string                 Runtime to use for this container
      --security-opt list              Security Options
      --shm-size bytes                 Size of /dev/shm
      --sig-proxy                      Proxy received signals to the process (default true)
      --stop-signal string             Signal to stop a container (default "SIGTERM")
      --stop-timeout int               Timeout (in seconds) to stop a container
      --storage-opt list               Storage driver options for the container
      --sysctl map                     Sysctl options (default map[])
      --tmpfs list                     Mount a tmpfs directory
  -t, --tty                            为容器重新分配一个伪输入终端,通常与 -i 同时使用
      --ulimit ulimit                  Ulimit options (default [])
  -u, --user string                    用户名或用户 id (format: <name|uid>[:<group|gid>])
      --userns string                  User namespace to use
      --uts string                     UTS namespace to use
  -v, --volume list                    绑定加载一个数据卷
      --volume-driver string           Optional volume driver for the container
      --volumes-from list              加载一个数据卷容器
  -w, --workdir string                 Working directory inside the container

查看容器

  1. 通过 docker ps 命令可以查看目前已经被创建的容器。默认情况下你只能看到正在运行中的容器列表,如果想要看到所有的容器,那么你可以使用 docker ps -a 来进行查看

     $ docker ps -a
     CONTAINER ID   IMAGE          COMMAND    CREATED        STATUS                    PORTS   NAMES
     8909b024ddd9   hello-world    "/hello"   1 second ago   Exited (0) 1 second ago           condescending_darwin
    

删除容器

  1. 当容器不再需要时,为了清除容器运行时所占用的磁盘空间,可以使用 docker rm 命令将容器中的内容全部删除

     $ docker rm 8909b024ddd9
    

停止容器

  1. 如果需要将一个正在运行时的容器停止,可以使用 docker stop 命令

     $ docker stop e40655248e77
    

启动容器

  1. 当一个容器因为一些原因停止后,如果想要再次运行起来,则可以使用 docker start 命令

     $ docker start e40655248e77
    

进入容器内部

  1. 有的时候,你可能需要进入容器内部去查看一些文件或执行一些相关操作,那么你可以通过 docker exec 命令来进入容器内部

     # it:进入当前容器,而且当前容器会占用控制台窗口
     $ docker exec -it e40655248e77 /bin/bash
     #已经进入容器内部
     [root@e40655248e77 /]# cat /etc/hostname
     e40655248e77
     [root@e40655248e77 /]# echo "现在就是在容器内了"
     现在就是在容器内了
     #退出容器
     [root@e40655248e77 /]# exit
    

并不是所有容器都支持进入容器内的,当不支持时执行 docker exec 命令可能会卡住,此时只需要按 ctrl + c 退出即可 如果需要从容器中退出只需要在容器中输入 exit 命令即可

查看容器日志

  1. 当我们部署一些自己的应用或第三方服务需要查看日志时,可以通过 docker logs 命令来查看容器中的日志

     $ docker logs e40655248e77
     64 bytes from 127.0.0.1: icmp_seq=670 ttl=64 time=0.035 ms
     64 bytes from 127.0.0.1: icmp_seq=671 ttl=64 time=0.032 ms
     64 bytes from 127.0.0.1: icmp_seq=672 ttl=64 time=0.048 ms
    

如果不带任何参数,默认会将容器中所有的日志输出,如果需要跟踪日志输出或只显示最新的指定数量的日志信息,即可使用 Usage 中的相关参数来指定即可

Usage:	docker logs [OPTIONS] CONTAINER

Fetch the logs of a container

Options:
      --details        Show extra details provided to logs
  -f, --follow         跟踪日志输出,类似于 tail -f 参数的作用
      --since string   按照时间切分日志,切分格式: (e.g. 2013-01-02T13:23:37) 或 (e.g. 42m for 42 minutes)
      --tail string    显示最新的指定数量的
  -t, --timestamps     显示时间戳
      --until string   显示某个时间之后的日志 (e.g. 2013-01-02T13:23:37) or relative (e.g. 42m for 42 minutes)

数据卷

  1. 当在容器中运行一些关键的应用如MySQL、Redis等服务,其中都会存储着一些关键数据,这些数据是希望即使删除容器也不应该被删除的,此时便需要用到数据卷了。可以将数据卷理解为文件目录的映射,可以通过 Docker 提供的相关命令,来将主机中的某一个文件目录映射到容器中,此时在容器中操作该目录下的文件时,实际上操作的就是主机中的文件。
  2. 数据卷相当于是容器的虚拟文件系统和主机的真实文件系统之间的一个桥梁,建立数据卷就相当于是打通了容器于主机之间的文件交互通道,可以让容器运行时所产生的数据变更被保存到主机中,能够更方便的对数据进行备份以及保护

绑定方式

匿名绑定

  1. 在启动容器时直接使用 -v /container_dir 即可完成匿名绑定,匿名绑定的方式将在 Docker 的 volumes 目录下生成一个 sha256 的字符串作为目录名,且指定的 /container_dir 中的文件或目录会被保存在该处,匿名绑定的 volume 在容器被删除的时候,数据卷也会被删除

     # 运行nginx这个服务,如果没有安装包则自动下载,并在容器的volumes目录下自动生成 ”sha256字符串/www/test“目录,然后自动映射到主机的某个目录下
     $ docker run --rm -d -p 80:80 -v /www/test nginx
     f46e0e5aeacfabcf59d70e73acc13ce9db66c08158f58baaf60d2d5babffa7c3
    
  2. 匿名绑定方式由于不知道主机的路径名称,因此如果需要查看数据卷在主机的哪个位置,需要使用 docker inspect -f '' container_id 来查看
  3. 即:启动容器并指定容器的某个路径,则生成该路径编码到容器volumes目录下,并自动映射到主机某个目录下。

具名绑定

  1. 同样是启动容器时绑定一个数据卷,不同的是可以为该数据卷起个名字 -v volume-name:container_dir,通过名字你可以快速的定位并管理这些 volume

      # 运行nginx这个服务,如果没有安装包则自动下载,并在容器的volumes目录下自动生成 ”sha256字符串/www/test“目录,然后映射到主机的某个路径下的nginx-www文件目录下
     $ docker run --rm -d -p 80:80 -v nginx-www:/www/test nginx
     13f9d01f9e70970235a7b8fdc692f7afdcdecaaff985425d99c8a8b4d1cd7224
    

Bind Mount

  1. 绑定并加载主机的某个文件目录到容器中,这种方式是平常最常用的。在容器启动时使用 -v host_dir:container_dir 的格式来完成映射
  2. 场景举例分析:(容器中部署一个nginx服务)
    1. nginx有2个东西需要经常修改,一个是nginx.conf,一个是html文件目录下的内容,html文件目是在nginx.conf配置文件中指定的
    2. 由于容器可以删除,下次重新启动容器还要重新配置nginx.conf、html文件目录下的内容,那么最好是将nginx.conf与html文件目录映射到主机物理地址,这样容器后序就可以随便删除了
    3. 执行命令

       # 运行了一个nginx容器,然后将本机目录下的html文件路径`/www/wolfcode` 与容器html文件路径’/www/wolfcode‘,进行映射。 同理将本机目录下的conf文件路径`/etc/nginx/nginx.conf` 与容器conf文件路径’/etc/nginx/nginx.conf‘,进行映射
       $ docker run --rm -d -p 80:80 -v /www/wolfcode:/www/wolfcode -v /etc/nginx/nginx.conf:/etc/nginx/nginx.conf nginx
      
      1. -p 80:80:将容器的80端口映射到主机的80端口
    4. 将主机目录映射到容器中以后,在容器中读取到的就是主机上的文件,同时你可以在参数后配置 :ro:rw 方式来控制容器内是否可以针对该数据卷进行读写操作,如 -v /www/wolfcode:/usr/share/nginx/html:ro 则表示容器中对 /usr/share/nginx/html 目录中的文件只有只读权限

数据卷管理

  1. Docker 为我们提供了一些专门用于管理数据卷的命令 docker volume,通过下面的 Usage 来查看相关命令的使用

     Usage:	docker volume COMMAND
     Manage volumes
     Commands:
       create      创建一个数据卷
       inspect     显示一个或多个数据卷的详细信息
       ls          查看目前已有的数据卷列表
       prune       删除所有本地没有被使用的数据卷
       rm          删除一个或多个数据卷
    

构建镜像

  1. Docker 提供了两种方式让我们来创建镜像,一种是将一个被修改后的容器重新打包为一个镜像,还有一种更常用的方式就是 Dockerfile,你可以利用 Dockerfile 构建一个属于你应用的专属镜像,只需要按照规定的格式完成相关的配置即可

容器构建镜像

  1. 有的时候你可能需要对一个已经运行的容器内的环境做出一些修改,而你也希望之后即使删除这个容器也能够保存这些变动,便于下次再启动一个新的容器,此时便可以利用 docker commit 命令将一个容器重新打包为一个镜像,这样下次便可以直接基于这个新的镜像来构建容器了

     # -m "描述内容“ 镜像id 仓库名称/镜像名称:版本号
     $ docker commit -m "build my centos" 88468edb2a4b wolf/centos:7
     sha256:ff800663234ab0eb0d821b196839fa24133df8f3c17dd70854d6c45a25aa0c09
        
     $ docker images
     REPOSITORY            TAG                 IMAGE ID            CREATED              SIZE
     wolf/centos           7                   ff800663234a        About a minute ago   203MB
    

Dockerfile构建镜像。

  1. Docker 为我们提供了一套约定的配置文件,该文件的作用就是描述构建镜像时所需要进行的相关操作,你只需要按照约束配置好需要构建的镜像的相关指令信息,并且将该文件的名字命名为 Dockerfile,那么你就可以直接使用 docker build 命令让 Docker 帮我们完成镜像的构建操作
  2. Dockerfile 提供了许多构建镜像相关的指令,下面的是一些常用指令,其他的可以从 Docker 官方文档 查看

     FROM 指定基础镜像,依赖于哪个镜像
     MAINTAINER 指定维护者信息
     RUN 在构建镜像的过程中,需要执行哪些命令;即在要执行的命令前加上RUN即可
     ADD 即往容器中copy文件,copy后会自动解压该文件
     WORKDIR 设置当前的工作目录,类似cd
     VOLUME 设置卷,挂载主机目录,就是前面的数据卷
     EXPOSE 暴露一些端口等,容器运行后需要暴露一些端口
     CMD/ENTRYPOINT 指定容器启动后默认要执行的命令
        
     ********举例********
     # 基于哪个镜像
     From openjdk:8
        
     # 维护者
     MAINTAINER Leon <liugang@wolfcode.cn>
        
     # 复制文件到容器,将代码目录下(target/*-server*)的jar包,复制到容器中,然后重命名为app.jar
     ADD target/*-server*.jar /app.jar
        
     # 环境变量:JVM 调优参数
        
     # 配置容器启动后执行的命令
     CMD ["java","-jar","/app.jar"]
    
  3. 通过以上文件即可构建一个具有 JDK8 的且包含了一个 java 应用的容器,在项目根目录创建一个 Dockerfile 文件,打开控制台并输入以下命令进行构建镜像

     # -t:构建镜像之后的名字    最后一个点"." 指的是Dockerfile这个文件的目录。由于Dockerfile在根目录,所以这里直接就是. 或者./
     $ docker build -t demo-server:1.0.0 .
    

docker build 命令的使用格式如下

Usage:	docker build [OPTIONS] DOCKERFILE_PATH | URL | -

Build an image from a Dockerfile

Options:
      --add-host list           Add a custom host-to-IP mapping (host:ip)
      --build-arg list          Set build-time variables
      --cache-from strings      Images to consider as cache sources
      --cgroup-parent string    Optional parent cgroup for the container
      --compress                Compress the build context using gzip
      --cpu-period int          Limit the CPU CFS (Completely Fair Scheduler) period
      --cpu-quota int           Limit the CPU CFS (Completely Fair Scheduler) quota
  -c, --cpu-shares int          CPU shares (relative weight)
      --cpuset-cpus string      CPUs in which to allow execution (0-3, 0,1)
      --cpuset-mems string      MEMs in which to allow execution (0-3, 0,1)
      --disable-content-trust   Skip image verification (default true)
  -f, --file string             Name of the Dockerfile (Default is 'PATH/Dockerfile')
      --force-rm                Always remove intermediate containers
      --iidfile string          Write the image ID to the file
      --isolation string        Container isolation technology
      --label list              Set metadata for an image
  -m, --memory bytes            Memory limit
      --memory-swap bytes       Swap limit equal to memory plus swap: '-1' to enable unlimited swap
      --network string          Set the networking mode for the RUN instructions during build (default "default")
      --no-cache                Do not use cache when building the image
      --pull                    Always attempt to pull a newer version of the image
  -q, --quiet                   Suppress the build output and print image ID on success
      --rm                      Remove intermediate containers after a successful build (default true)
      --security-opt strings    Security options
      --shm-size bytes          Size of /dev/shm
  -t, --tag list                Name and optionally a tag in the 'name:tag' format
      --target string           Set the target build stage to build.
      --ulimit ulimit           Ulimit options (default [])

容器镜像私有仓库

  1. 在公司中通常会搭建一个私有仓库,用于管理公司内部的镜像。为了便于服务的部署,我们会在开发完成后将服务打包成镜像,并且将其推送到公司的私有镜像仓库,当我们需要在公司内任意环境部署服务时,只需要从私有仓库中下载镜像并运行容器即可
  2. 部署流程:项目开发 > 打包 > 发布到仓库 > 拉取到对应环境部署

配置

  1. 为了容器安全考虑,Docker 默认是拒绝将镜像推送到除 Docker 官方仓库以外的其他仓库的,因此我们需要将公司的私有仓库添加到授信的仓库列表,这样才能对仓库进行后续操作
  2. 修改 /etc/docker/daemon.json 文件,在其中加入 insecure-registries 配置

     $ vi /etc/docker/daemon.json
     # 加入如下配置即可,私有仓库的地址:端口号
     {
       "insecure-registries": ["192.168.113.103:20000"]
     }
     $ systemctl daemon-reload
     $ systemctl restart docker
    

认证

  1. 通常来说,私有仓库是需要对用户进行认证的,因此在进行操作之前,我们需要先使用 docker login 命令来进行登录认证,认证通过以后才能正常操作仓库

     # gz-java 私有仓库的账号
     $ docker login -u gz-java 192.168.113.103:20000 
     # gz.java 私有仓库的密码
     password: gz.java
     Login Succeeded
    

推送到仓库

要将一个镜像推送到仓库,需要分成两个步骤

  1. 打标签: 首先需要为镜像重新打一个 tag

     # 仓库地址/仓库名称/镜像名称:版本号
     $ docker tag demo-server:1.0.0 192.168.113.103:20000/java/demo-server:1.0.0
    
  2. 推送: 将新打 tag 的镜像推送到仓库

     $ docker push 192.168.113.103:20000/java/demo-server:1.0.0
     The push refers to repository [192.168.113.103:20000/java/demo-server]
     18718166a51a: Pushed
     edf3aa290fb3: Pushed
     1.0.0: digest: sha256:1fb403755a7c5bdb50b279a849604d0ab1131943a34c0ecbd9fa799ee3b49da9 size: 236
    

从仓库拉取

  1. 当项目发布到仓库以后,由于已经配置了可信的私有仓库,因此在拉取镜像时会自动的从私有仓库先进行拉取

     docker pull 192.168.113.103:20000/java/demo-server:1.0.0
    

容器编排

  1. 有的时候我们会需要涉及到在一台机器部署多个容器,那么此时再手动的每次输入相关的一堆配置命令再来启动容器,还是产生了很多无意义的重复性劳动。针对单机的多容器部署的情况,Docker 为我们提供了一个单机版本的服务编排工具 docker-compose
  2. Docker-Compose 可以高效便捷的管理单机上运行的所有容器,它通过 yaml 配置文件的方式完成之前执行 docker run 命令所设置的所有参数,你可以先针对单机上的所有容器进行相关配置,配置完成后即可使用 docker-compose 对单机多容器进行高效的管理

     version: "2"
     services:
       nginx:
       	conatiner_name: "nginx-demo"
         image: "nginx"
         volumes:
         	- /www/wolfcode:/usr/share/nginx/html:ro
         	- /etc/nginx/nginx.conf:/etc/nginx/nginx.conf
         networks:
           - demo-net
         ports:
         	- "80:80"
         environment:
         	NGINX_HOME=/usr/local/nginx
         restart: on-failure:3
     networks:
       demo-net:
     		driver: bridge
    
  3. 详细配置查看 Docker Compose 官方文档
  4. 通过以上的配置文件,即可完成对容器的统一管理,并且配合 docker-compose 所提供的命令即可完成容器的创建、启动、停止和删除等等相关操作

     Define and run multi-container applications with Docker.
        
     Usage:
       docker-compose [-f <arg>...] [options] [COMMAND] [ARGS...]
       docker-compose -h|--help
        
     Options:
       -f, --file FILE             Specify an alternate compose file (default: docker-compose.yml)
       -p, --project-name NAME     Specify an alternate project name (default: directory name)
       --verbose                   Show more output
       -v, --version               Print version and exit
       -H, --host HOST             Daemon socket to connect to
        
       --tls                       Use TLS; implied by --tlsverify
       --tlscacert CA_PATH         Trust certs signed only by this CA
       --tlscert CLIENT_CERT_PATH  Path to TLS certificate file
       --tlskey TLS_KEY_PATH       Path to TLS key file
       --tlsverify                 Use TLS and verify the remote
       --skip-hostname-check       Don't check the daemon's hostname against the name specified
                                   in the client certificate (for example if your docker host
                                   is an IP address)
        
     Commands:
       build              构建或重新构建一个服务
       bundle             Generate a Docker bundle from the Compose file
       config             验证并查看 compose 文件
       create             创建一个服务
       down               停止并删除容器、网络、镜像和数据卷
       events             Receive real time events from containers
       exec               在一个运行中的容器执行命令
       help               获取帮助信息
       kill               关闭一个容器
       logs               显示服务的日志信息
       pause              暂停一个服务
       port               打印一个端口绑定的公开端口
       ps                 查看容器列表
       pull               拉取镜像
       push               推送镜像
       restart            重启容器
       rm                 删除已经停止的容器
       run                运行一个一次性执行的命令
       scale              设置服务的容器数量
       start              启动服务
       stop               停止服务
       unpause            恢复一个暂停的服务
       up                 创建并启动一个容器
       version            显示 compose 的版本信息
    

Docker Compose

Compose 简介

  1. Compose 是用于定义和运行多容器 Docker 应用程序的工具。通过 Compose,您可以使用 YML 文件来配置应用程序需要的所有服务。然后,使用一个命令,就可以从 YML 文件配置中创建并启动所有服务。

Compose 安装

  1. 安装命令

     sudo curl -L "http://mirrors.aliyun.com/docker-toolbox/linux/compose/1.9.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
    
  2. 要安装其他版本的 Compose,请替换 1.24.1。
  3. 将可执行权限应用于二进制文件:

     sudo chmod +x /usr/local/bin/docker-compose
    
  4. 创建软链:

     sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
    
  5. 测试是否安装成功:

     docker-compose --version
    
  6. 注意: 对于 alpine,需要以下依赖包: py-pip,python-dev,libffi-dev,openssl-dev,gcc,libc-dev,和 make。

Docker Swarm

  1. Docker Compose:帮助在 同一个节点 上部署多个容器。
  2. Docker Swarm:多台机器上部署容器。开箱即用,快速部署容器。偏重容器部署
  3. K8s:社区活跃度高,组件丰富。微服务化,偏重应用的部署
  4. compose支持在 同一节点 上部署,swarm支持在多个节点上部署容器。这两者都是docker原生支持的docker集群部署方式,开箱即用,比较方便,偏重于容器的部署。
  5. Docker Swarm 和 Docker Compose 一样,都是 Docker 官方容器编排项目,但不同的是,Docker Compose 是一个在单个服务器或主机上创建多个容器的工具,而 Docker Swarm 则可以在多个服务器或主机上创建容器集群服务,对于微服务的部署,显然 Docker Swarm 会更加适合。
  6. 从 Docker 1.12.0 版本开始,Docker Swarm 已经包含在 Docker 引擎中(docker swarm),并且已经内置了服务发现工具,我们就不需要像之前一样,再配置 Etcd 或者 Consul 来进行服务发现配置了。
  7. swarm偏重的是容器的部署,而k8s偏重于应用的部署。k8s对容器的所有操作都渗透着为应用而服务的理念,比如pod是为了让联系紧密但又不适合部署在一起的应用分别部署在不同docker里面,但docker之间共享volume和network namespace方式,以便实现紧密地“交流”,在比如service是为了隐藏pod(容器的集合,下文会介绍到)的网络细节,让pod提供固定的访问入口,从而方便地让其他应用访问等。
  8. 在swarm中,被创建、调度和管理的最小单元就是docker。在k8s中,最小单元则是pod。
Table of Contents