基本概括

容器背景

程序运行的基础环境

我们的程序首先在开发环境开发,然后需要部署到测试环境交给测试人员测试,最后需要由运维人员部署到生产环境正式运行,在这个过程中任何一个环境如果和其他环境不一致,则会出现开发阶段能运行的程序在测试阶段或生产阶段不能够正常运行,这就是“软件跨环境迁移”问题。

JavaEE程序依赖的基础环境:JDK、tomcat、数据库、中间件、操作系统、配置文件(代码配置、JDK配置、tomcat配置、操作系统配置)等等

因此面临的问题

  • 复杂的系统运维

    • 开发环境、测试环境和生产环境的很难保持高度一致,由环境不一致而导致的软件故障,很难解决
  • 软件交付和部署流程繁琐

    • 传统的应用开发完成后,需要提供一堆安装程序和配置说明文档,安装部署后需根据配置文档进行繁杂的配置才能正常运行
  • 服务器扩缩容流程繁琐、成本巨大

解决方案:容器化

于是它出现了,Docker可以让开发者构建应用程序时,将应用程序与其所依赖的环境一起打包到一个容器中,然后一一交付整个环境而不仅仅是代码。

这样一个带环境的程序包就是一个容器,容器可以解决软件跨环境迁移的问题。

Docker概念

开源容器引擎:docker是基于Go语言实现的开源容器引擎。2013年出现,DotCloud公司开发(现在的Docker公司)

集装箱:可以将每个容器看成是一个集装箱,包含程序以及程序运行所依赖的所有环境和配置。

  • 标准化:每个容器都是标准化、可移植的,因为他们直接运行在宿主机的内核上
  • 隔离:容器互相隔离,互不干扰,独立运行
  • 高性能:容器性能开销极低,可以实现分钟级甚至秒级的部署和启动
  • 版本:CE(Community Edition:社区版)和EE(Enterprise Edition:企业版)

Docker理念

Build,Ship and Run Any App,Anywhere

在任何地方构建、发布并运行任何应用程序(一次封装,到处运行)

安装准备

前提条件

Docker可以运行在Windows、Mac、CentOS、Ubuntu等操作系统上

Docker支持以下的CentOS版本:

  • CentOS 7 (64-bit)
  • CentOS 6.5 (64-bit) 或更高的版本

目前,CentOS 仅发行版本中的内核支持 Docker

Docker 运行在 CentOS 7 上,要求系统为64位、系统内核版本为 3.10 以上。

Docker 运行在 CentOS-6.5 或更高的版本的 CentOS 上,要求系统为64位、系统内核版本为 2.6.32-431 或者更高版本。

CentOS7 镜像

阿里云站点:http://mirrors.aliyun.com/centos/7/isos/x86_64/

每个链接都包括了镜像文件的地址、类型及版本号等信息

选择当前国家资源区站点下载,获取资源速度比较快

step1: 进入阿里云站点,选择 CentOS-7-x86_64-DVD-1804.iso下载

各个版本的ISO镜像文件说明:

CentOS-7-x86_64-DVD-1708.iso 标准安装版(推荐)

CentOS-7-x86_64-Everything-1708.iso 完整版,集成所有软件(以用来补充系统的软件或者填充本地镜像)

CentOS-7-x86_64-LiveGNOME-1708.iso GNOME桌面版

CentOS-7-x86_64-LiveKDE-1708.iso KDE桌面版

CentOS-7-x86_64-Minimal-1708.iso 精简版,自带的软件最少

CentOS-7-x86_64-NetInstall-1708.iso 网络安装版(从网络安装或者救援系统)

查看系统内核

uname命令用于打印当前系统相关信息(内核版本号、硬件架构、主机名称和操作系统类型等)。

uname -r
lsb_release -a

查看CentOS版本信息

cat /etc/redhat-release

CentOS7安装Docker

安装需要的软件包

yy -utils提供了yy-config-manager相关功能,device-mapper-persistent-data和lvm2是设备映射器驱动程序所需要的。

yum install -y yum-utils \
               device-mapper-persistent-data \
               lvm2

Docker下载

Docker下载地址

推荐阿里云

yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

更新yum软件包索引

我们在更新或配置yum源之后,通常都会使用yum makecache 生成缓存,这个命令是将软件包信息提前在本地缓存一份,用来提高搜索安装软件的速度

yum makecache fast

安装Docker CE

yum install -y docker-ce

启动Docker

systemctl start docker

Docker自启

systemctl enable docker

版本验证

docker version

允许当前用户直接运行 docker 命令

需要将当前用户加入 docker 用户组。这样每次运行 docker 命令的时候,就不需要加 sudo

sudo usermod -aG docker your_name

CentOS6.8安装docker

安装epel

docker依赖EPEL库,首先要确保已经安装epel仓库:

yum install -y epel-release
yum install -y docker-io

安装后的配置文件

/etc/sysconfig/docker

启动Docker

service docker start

版本验证

docker version

允许当前用户直接运行 docker 命令

需要将当前用户加入 docker 用户组。这样每次运行 docker 命令的时候,就不需要加 sudo

sudo usermod -aG docker your_name

卸载Docker

systemctl stop docker 
yum remove -y docker-ce
rm -rf /var/lib/docker

Docker架构

架构图

架构组成

Docker由三部分组成:Client客户端、DOCKER_HOST docker主机、Registry 镜像仓库服务器

  • DOCKER_HOST:docker主机

    • docker daemon:docker安装后,会以守护进程的形式存在,也就是后台运行的进程
    • Images:镜像:镜像可以用来创建 docker 容器,一个镜像可以创建很多容器
    • Containers:容器:镜像和容器的关系类似面向对象设计中的类和对象,镜像是容器的模板,容器是基于镜像创建出来的。容器可以被创建、启动、停止、删除等等。
  • Registry:镜像仓库服务器 https://hub.docker.com

    • 一个 docker Registry(仓库注册服务器) 中可以包含多个Repository(仓库);每个仓库可以包含多个标签/版本(Tag);每个标签对应一个镜像。
    • 仓库分为公开仓库(Public)和私有仓库(Private)两种形式

      • 公开仓库就是docker官方仓库
      • 私有仓库是自己搭建的docker私服
  • Client:docker终端

    • 安装好docker中,同时包含了docker客户端,客户端负责执行docker命令,发送给docker主机中的docker守护进程,例如:从仓库下载镜像,通过镜像创建容器等等。

容器镜像服务

是什么

从docker的官方镜像仓库服务器上下载docker的镜像速度很慢,因此我们可以配置国内的容器镜像服务,提升docker镜像的下载速度。

  • 阿里云
  • 腾讯云
  • 网易云

开通镜像服务

登录阿里云,搜索“容器镜像服务”,获取加速地址

hello-world

执行命令

docker run hello-world

流程原理: 首先在docker主机查找hello-world的镜像文件,如果本地不存在镜像文件,则从镜像仓库下载(pulling from library/hello-world)。

以镜像为模板创建docker容器并运行

没有配置镜像加速器的结果:

首先在docker主机查找hello-world的镜像文件,如果本地不存在镜像文件,则从镜像仓库下载。

因为docker官方的镜像仓库国内无法访问,所以访问超时(Timeout)

run的工作流程

Docker基本命令

版本信息

docker version

详细信息

docker info

帮助文档

docker --help #列出所有的docker命令
docker run --help #列出某一个docker命令的详细信息

启动docker服务

systemctl start docker

停止docker服务

systemctl stop docker

查看服务状态

systemctl status docker

重启docker服务

systemctl restart docker

开机自启动

systemctl enable docker

Docker镜像命令

列出本机镜像:docker images

基本命令

docker images

表头说明

  • REPOSITORY:镜像的名称
  • TAG:镜像的版本号
  • IMAGE ID:镜像ID
  • CREATED:镜像创建时间
  • SIZE:镜像大小

OPTIONS说明

docker images -q
  • -q:只显示镜像ID
  • --no-trunc :显示完整的镜像ID

查找镜像:docker search

基本命令

docker search tomcat

表头说明

  • NAME:镜像的名称
  • DESCRIPTION:镜像描述
  • STARS:点赞数量
  • OFFICIAL:是否是官方镜像
  • AUTOMATED:是否自动化构建,只要代码版本管理网站的项目有更新, 就会触发自动创建image.

OPTIONS说明

docker search -s 30 tomcat
#或
docker search --filter=stars=30 tomcat
  • -s:列出收藏数不小于指定值的镜像
  • --filter : 过滤器

下载镜像:docker pull

基本命令

docker pull tomcat

使用 docker images查看镜像列表,可以看到tomcat的体积非常大,因为这是一个独立的集装箱环境,包含了所有运行tomcat所必须的底层依赖。

下载指定版本

#例如
docker pull redis:3.2

删除镜像:docker rmi

基本命令

docker rmi tomcat
docker rmi reids:3.2 #删除指定版本的镜像
docker rmi 镜像id #根据镜像id删除镜像

强制删除

docker rmi -f hello-world #强制删除已经创建了实例的镜像,此时再次运行实例会重新下载镜像

批量删除

docker rmi tomcat redis #删除多个镜像,使用空格间隔不同的镜像名称
docker rmi -f $(docker images -q) #删除所有镜像

查看镜像详情:docker inspect

docker inspect tomcat:8.5.32 | grep -i version #查看镜像的具体版本,-i:忽略大小写

Docker容器命令

基本命令

列出容器:docker ps

docker ps #列出所有正在运行的容器,不包含已停止的容器
docker ps -a #列出当前所有已经创建的容器

表头说明

  • CONTAINER ID:容器id
  • IMAGE:创建容器的镜像
  • COMMAND:容器启动调用的命令
  • CREATED:容器创建时间
  • STATUS:容器的状态(Created/创建/Up启动/Exited退出)
  • PORTS:容器占用的端口
  • NAMES:容器名

OPTIONS说明

docker ps -qa #列出所有容器的编号
  • -a :列出当前所有已经创建的容器
  • -l :显示最近创建的一个容器
  • -n:显示最近n个创建的容器。 docker ps -n 3
  • -q:只显示容器编号

创建容器:docker create

docker create tomcat #根据镜像名创建一个容器
docker create --name tomcat1 tomcat ##根据镜像名创建一个容器,并为容器起一个别名tomcat1
docker create 镜像id #根据镜像id新建一个容器

启动容器:docker start

docker start tomcat1 #根据容器名启动一个容器
docker start 容器id #根据容器id启动一个容器

创建并启动容器:docker run

相当于 docker create + docker start

当本地镜像不存在时,相当于 docker pull + docker create + docker start

docker run tomcat #根据镜像名创建一个容器,并启动
docker run --name tomcat2 tomcat #为容器起一个别名tomcat2,并启动

停止容器:docker stop

docker stop tomcat1 #根据容器名停止一个容器

强制停止容易:docker kill

docker kill tomcat1 #根据容器名强制停止一个容器

重启容器:docker restart

docker restart tomcat2 #根据容器名重启一个容器

删除容器:docker rm

docker rm tomcat1 #删除未启动的容器 
docker rm -f tomcat2 #强制删除已启动的容器
docker rm -f $(docker ps -qa) #删除所有容器

启动交互式容器

启动CentOS

docker run centos

默认情况下,centos启动后无事可做,docker会立即停止刚刚启动的centos容器,如下图:

使用 docker run centos 运行一个centos容器,随即使用 docker ps 列出正在运行的容器列表,未发现刚刚运行的centos;

使用 docker ps -a 列出全部容器列表,发现centos容器已停止

交互式启动:-it

docker run -it --name centos1 centos #启动后,当前命令行会进入到centos容器内部

OPTIONS说明

  • -i:保持容器一直运行,但命令行会挂起,通常与 -t 同时使用;
  • -t:为容器分配一个伪输入终端,通常与 -i 同时使用;

此时可以像在本地服务器上一样在容器内执行Linux命令,例如查看内核版本号、查看Linux发行版本号等

(如果在宿主机上也查看内核版本号,那么可以发现容器使用的是宿主机的内核)

退出容器

容器不停止退出

Ctrl+p, q #容器不停止退出,此时执行docker ps,可以看到centos还在运行

容器停止并退出

exit #容器停止退出,此时执行docker ps -a,发现centos已停止

进入容器:docker attach

当容器未停止时,在宿主机中可以进入到容器内部命令行

docker attach centos1

执行命令:docker exec

在容器外部执行命令,使命令在容器内部运行,并返回结果

#确保容器是启动状态,并且当前命令行在容器外部的宿主机上
docker exec -it centos1 cat /etc/redhat-release

比较下面两个命令的执行结果:第一个显示的是centos容器的版本,第二个显示的是宿主机centos的版本

启动守护式容器

启动tomcat

默认情况下,tomcat的启动会占用当前命令行窗口,并进入挂起状态

docker run tomcat

守护式启动:-d

我们可以以守护进程的方式启动tomcat容器

docker run -d --name tomcat1 tomcat  #在后台启动tomcat,不占用命令行资源

映射容器端口:-p

默认情况下,我们无法通过docker所在的宿主机访问tomcat容器的8080端口,需要将8080端口映射到宿主机的某一个端口上

docker run -d -P tomcat #(大写P)随机端口映射
docker run -d -p 7777:8080 --name tomcat2 tomcat #(小写P)将容器端口发布到主机7777端口
docker inspect tomcat2 #inspect可以用于镜像,也可以用于容器,这里可以查看容器tomcat2的详情

OPTIONS说明

  • -P: 随机端口映射;
  • -p: 指定端口映射,有以下四种格式

    • ip:hostPort:containerPort
    • hostPort:containerPort
    • ip::containerPort:主机随机分配端口映射容器的指定端口
    • containerPort:主机随机分配端口映射容器的指定端口

访问前面启动的tomcat容器:如 http://192.168.100.101:7777,发现报告404错误,

原因是docker latest版本的tomcat下的webapps中没有部署任何默认项目,因此启动浏览器无法访问tomcat默认主页面

执行命令:docker exec

进入到容器内部的文件系统

docker exec -it tomcat2 /bin/bash

下载8.5.32版本的docker tomcat镜像

Ctrl+p, q #退出tomcat容器
docker pull tomcat:8.5.32
docker run -d -p 8888:8080 --name tomcat3 tomcat:8.5.32

访问:http://192.168.100.101:8888 ,可以看到tomcat的默认主页

查看容器详情:docker inspect

docker inspect tomcat3

Docker数据卷

什么是数据卷

出于效率等一系列原因,docker 容器的文件系统在宿主机上存在的方式很复杂,这会带来下面几个问题:

  • 当容器删除时,容器中产生的数据将丢失:例如,MySQL容器损坏无法启动,需要删除容器重新创建,那么数据库数据将会丢失

  • 无法在多个容器之间共享数据:

例如,Tomcat集群部署成功后,无法共享程序文件

数据卷的概念

为了解决以上的问题,docker 引入了数据卷(volume) 机制。数据卷是存在于一个或多个容器中的特定文件或文件夹,这个文件或文件夹以独立于 docker 文件系统的形式存在于宿主机中。

  • 当容器删除时,容器中的数据可以被持久化:

  • 在多个容器之间共享数据:

数据卷的最大特点是:其生存周期独立于容器的生存周期。使用数据卷可以在多个容器之间共享数据。

配置数据卷目录

挂载数据卷

将宿主机根目录中的dataVolumeHost挂载到容器根目录中的dataVolumeContainer

docker run -it -v /dataVolumeHost:/dataVolumeContainer --name centos2 centos:7

OPTIONS说明

  • -v:挂载数据卷
  • 格式:/宿主机目录(文件):/容器内目录(文件)
  • 目录必须是绝对路径
  • 如果目录不存在,则自动创建
  • 可以挂载多个数据卷

查看数据卷是否挂载成功

此时可以分别查看宿主机和容器的根目录,发现分别生成了数据卷目录

执行命令 docker inspect 可以查看数据卷已挂载

docker inspect centos2

数据共享

首先进入容器,在容器的数据卷挂载目录中创建文件并写入内容

然后退出容器,查看宿主机挂载目录,可以看到同步更新的文件

数据的同步

首先停止容器

然后在宿主机修改共享数据

接下来启动前面的容器,查看共享数据文件,发现数据在容器中同步

数据的持久化

首先删除容器

然后在宿主机修改共享数据

接着重新创建容器并挂载数据卷

发现数据在容器中恢复

一个容器挂载多个数据卷

docker run -it \
-v /dataVolumeHost31:/dataVolumeContainer31 \
-v /dataVolumeHost32:/dataVolumeContainer32 \
--name centos3 centos:7

两个容器挂载同一个数据卷

docker run -it -v /dataVolumeHost:/dataVolumeContainer4 --name centos4 centos:7
docker run -it -v /dataVolumeHost:/dataVolumeContainer5 --name centos5 centos:7

数据卷容器

什么是数据卷容器

多容器数据交换的方式

  • 多个容器挂载宿主机上的同一个数据卷目录
  • 多个容器挂载宿主机上的同一个数据卷容器

    • 首先将宿主机上的数据卷目录挂载到容器1上
    • 然后将容器1挂载到容器2和容器3上
    • 此时宿主机上的数据卷目录就会自动挂载到容器2和容3上,即使容器3宕机,也不会影响其他两个容器的运行

数据卷容器的概念

数据卷容器也是一个容器,但是这个容器的作用是专门提供数据卷供其他容器挂载,其它容器通过挂载这个数据卷容器实现数据共享。

配置数据卷容器

创建数据卷容器

当 -v 参数后面只有一个目录的时候,表示只设置容器中的数据卷目录,而宿主机中的数据卷目录会被自动分配

docker run -it -v /volume --name c1 centos:7

容器创建成功后,可以查看数据卷目录的分配情况

docker inspect c1

挂载数据卷容器

docker run -it --volumes-from c1 --name c2 centos:7
docker run -it --volumes-from c1 --name c3 centos:7

OPTIONS说明

--volumes-from:将当前容器挂载到指定的数据卷容器上

容器创建成功后,可以查看c1和c2的数据卷目录的分配情况,发现和c1使用的是同一个宿主机的文件目录

docker inspect c2
docker inspect c3

测试数据共享

vi /var/lib/docker/volumes/06e480611281a60059aeb574dc2b455645d896858d7c7a849c65cf2113a35df3/_data/data.txt # 写入 hello volume container
docker exec -it c2 cat /volume/data.txt
docker exec -it c3 cat /volume/data.txt

Docker-Compose

概念介绍

Docker-Compose项目是Docker官方的开源项目,负责实现对Docker容器集群的快速编排。

Docker-Compose将所管理的容器分为三层,分别是工程(project),服务(service)以及容器(container)。

Docker-Compose运行目录下的所有文件(docker-compose.yml,extends文件或环境变量文件等)组成一个工程,若无特殊指定工程名即为当前目录名。一个工程当中可包含多个服务,每个服务中定义了容器运行的镜像,参数,依赖。

一个服务当中可包括多个容器实例,Docker-Compose并没有解决负载均衡的问题,因此需要借助其它工具实现服务发现及负载均衡。

Docker-Compose的工程配置文件默认为 docker-compose.yml,当然也可以通过环境变量 COMPOSE_FILE-f 参数自定义配置文件。

使用一个Dockerfile模板文件,可以让用户很方便的定义一个单独的应用容器。在工作中,经常会碰到需要多个容器相互配合来完成某项任务的情况。例如要实现一个Web项目,除了Web服务容器本身,往往还需要再加上后端的数据库服务容器,甚至还包括负载均衡容器等。Compose允许用户通过一个单独的docker-compose.yml模板文件(YAML 格式)来定义一组相关联的应用容器为一个项目(project)。

Docker-Compose项目由Python编写,调用Docker服务提供的API来对容器进行管理。因此,只要所操作的平台支持Docker API,就可以在其上利用Compose来进行编排管理。

安装docker-compose

sudo curl -L https://get.daocloud.io/docker/compose/releases/download/1.27.4/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
docker-compose --version
docker-compose [-f <arg>...] [options] [COMMAND] [ARGS...]

命令选项:

  • -f --file: FILE指定Compose模板文件,默认为docker-compose.yml
  • -p --project-name: NAME 指定项目名称,默认使用当前所在目录为项目名
  • --verbose: 输出更多调试信息
  • -v,-version: 打印版本并退出
  • --log-level LEVEL: 定义日志等级(DEBUG, INFO, WARNING, ERROR, CRITICAL)

常用命令

启动docker-compose:docker-compose up -d

列出所有容器:docker-compose ps

停止容器:docker-compose stop 停止正在运行的容器,可以通过 docker-compose start 再次启动

查看日志:docker-compose logs

重启所有容器:docker-compose restart

暂停某个容器:docker-compose pause [SERVICE...]

进入某个容器:docker-compose exec [options] SERVICE COMMAND [ARGS...]

选项包括:

  • -d 分离模式,后台运行命令。
  • –privileged 获取特权。
  • –user USER 指定运行的用户。

docker-compose.yml

Compose允许用户通过一个 docker-compose.yml 模板文件(YAML 格式)来定义一组相关联的应用容器为一个项目(project)。

Compose模板文件是一个定义服务、网络和卷的YAML文件。Compose模板文件默认路径是当前目录下的 docker-compose.yml,可以使用 .yml.yaml 作为文件扩展名。

Docker-Compose标准模板文件应该包含version、services、networks 三大部分,最关键的是services部分。

注意:yml 语法的格式是非常重要的,缩进也要得当。

version: '3'
services: 
  mysql1:
    image: mysql
    container_name: mysql1
    environment: 
      - MYSQL_ROOT_PASSWORD=123456
    ports: 
     - 39111:3306

  mysql2:
    image: mysql
    container_name: mysql2
    environment: 
      - MYSQL_ROOT_PASSWORD=123456
    ports: 
       - 39112:3306

其中还有一些比较常用的属性

depends_on

在使用Compose时,最大的好处就是少打启动命令,但一般项目容器启动的顺序是有要求的,如果直接从上到下启动容器,必然会因为容器依赖问题而启动失败。例如在没启动数据库容器的时候启动应用容器,应用容器会因为找不到数据库而退出。depends_on标签用于解决容器的依赖、启动先后的问题

version: '3'
services:
  web:
    build: .
    depends_on:
      - db
      - redis
  redis:
    image: redis
  db:
    image: postgres

上述YAML文件定义的容器会先启动 redis 和 db 两个服务,最后才启动 web 服务。

volumes

挂载数据卷

volumes:
  - /opt/data:/var/lib/mysql

volumes_from

挂载数据卷容器

volumes_from:
  - service_name   
    - container_name

links

链接到其它服务中的容器。在 Redis 搭建主从架构时我便使用到了它。有兴趣的朋友看看我写过的一个 Redis 笔记

links:
  - db
  - db:database
  - redis

build

服务除了可以基于指定的镜像,还可以基于一份Dockerfile,在使用up启动时执行构建任务,构建标签是build,可以指定Dockerfile所在文件夹的路径。

Compose将会利用Dockerfile自动构建镜像,然后使用镜像启动服务容器。

build: /path/to/build/dir

 也可以是相对路径,只要上下文确定就可以读取到Dockerfile。

build: ./dir

 设定上下文根目录,然后以该目录为准指定Dockerfile。

build:
  context: ../
  dockerfile: path/of/Dockerfile

如果同时指定image和build两个标签,那么 Compose 会构建镜像并且把镜像命名为 image 值指定的名字。


Last modification:September 4, 2021
如果觉得我的文章对你有用,请随意赞赏