基本概括

容器背景

程序运行的基础环境

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

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

image-20230713171331829

因此面临的问题

  • 复杂的系统运维
    • 开发环境、测试环境和生产环境的很难保持高度一致,由环境不一致而导致的软件故障,很难解决
  • 软件交付和部署流程繁琐
    • 传统的应用开发完成后,需要提供一堆安装程序和配置说明文档,安装部署后需根据配置文档进行繁杂的配置才能正常运行
  • 服务器扩缩容流程繁琐、成本巨大

解决方案:容器化

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

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

image-20230713171405557

Docker概念

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

image-20230713171439660

image-20230713171454045

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

image-20230713171526787

  • 标准化:每个容器都是标准化、可移植的,因为他们直接运行在宿主机的内核上
  • 隔离:容器互相隔离,互不干扰,独立运行
  • 高性能:容器性能开销极低,可以实现分钟级甚至秒级的部署和启动
  • 版本: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命令用于打印当前系统相关信息(内核版本号、硬件架构、主机名称和操作系统类型等)。

1
2
uname -r
lsb_release -a

查看CentOS版本信息

1
cat /etc/redhat-release

CentOS7安装Docker

安装需要的软件包

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

1
2
3
yum install -y yum-utils \
device-mapper-persistent-data \
lvm2

Docker下载

Docker下载地址

推荐阿里云

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

更新yum软件包索引

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

1
yum makecache fast

安装Docker CE

1
yum install -y docker-ce

启动Docker

1
systemctl start docker

Docker自启

1
systemctl enable docker

版本验证

1
docker version

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

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

1
sudo usermod -aG docker your_name

CentOS6.8安装docker

安装epel

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

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

安装后的配置文件

1
/etc/sysconfig/docker

启动Docker

1
service docker start

版本验证

1
docker version

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

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

1
sudo usermod -aG docker your_name

卸载Docker

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

Docker架构

架构图

image-20230713171626649

架构组成

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镜像的下载速度。

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

开通镜像服务

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

image-20230713171648266

image-20230713171719669

hello-world

执行命令

1
docker run hello-world

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

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

image-20230713171849783

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

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

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

image-20230713171905219

run的工作流程

image-20230713171945259

Docker基本命令

版本信息

1
docker version

详细信息

1
docker info

帮助文档

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

启动docker服务

1
systemctl start docker

停止docker服务

1
systemctl stop docker

查看服务状态

1
systemctl status docker

重启docker服务

1
systemctl restart docker

开机自启动

1
systemctl enable docker

Docker镜像命令

列出本机镜像:docker images

基本命令

1
docker images

表头说明

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

OPTIONS说明

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

基本命令

1
docker search tomcat

image-20230713172002980

表头说明

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

OPTIONS说明

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

下载镜像:docker pull

基本命令

1
docker pull tomcat

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

image-20230713172017746

下载指定版本

1
2
#例如
docker pull redis:3.2

删除镜像:docker rmi

基本命令

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

强制删除

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

批量删除

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

查看镜像详情:docker inspect

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

image-20230713172028732

Docker容器命令

基本命令

列出容器:docker ps

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

img

表头说明

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

OPTIONS说明

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

创建容器:docker create

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

启动容器:docker start

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

创建并启动容器:docker run

相当于 docker create + docker start

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

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

停止容器:docker stop

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

强制停止容易:docker kill

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

重启容器:docker restart

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

删除容器:docker rm

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

启动交互式容器

启动CentOS

1
docker run centos

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

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

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

image-20230713172044184

交互式启动:-it

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

OPTIONS说明

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

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

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

image-20230713172107944

退出容器

容器不停止退出

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

容器停止并退出

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

进入容器:docker attach

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

1
docker attach centos1

执行命令:docker exec

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

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

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

image-20230713172152900

启动守护式容器

启动tomcat

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

1
docker run tomcat

守护式启动:-d

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

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

映射容器端口:-p

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

image-20230713172211376

1
2
3
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

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

1
docker exec -it tomcat2 /bin/bash

下载8.5.32版本的docker tomcat镜像

1
2
3
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

1
docker inspect tomcat3

Docker数据卷

什么是数据卷

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

  • 当容器删除时,容器中产生的数据将丢失:例如,MySQL容器损坏无法启动,需要删除容器重新创建,那么数据库数据将会丢失
image-20230713172227368
  • 无法在多个容器之间共享数据:

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

image-20230713172305559

数据卷的概念

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

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

    image-20230713172327531

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

    image-20230713172340461

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

配置数据卷目录

挂载数据卷

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

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

OPTIONS说明

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

查看数据卷是否挂载成功

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

image-20230713172518015

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

1
docker inspect centos2

image-20230713172529171

数据共享

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

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

image-20230713172546548

数据的同步

首先停止容器

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

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

image-20230713172601509

数据的持久化

首先删除容器

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

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

发现数据在容器中恢复

image-20230713172614434

一个容器挂载多个数据卷

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

image-20230713172627624

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

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

image-20230713172643157

数据卷容器

什么是数据卷容器

多容器数据交换的方式

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

数据卷容器的概念

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

配置数据卷容器

创建数据卷容器

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

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

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

1
docker inspect c1

image-20230713172730945

挂载数据卷容器

1
2
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使用的是同一个宿主机的文件目录

1
2
docker inspect c2
docker inspect c3

image-20230713172748194

image-20230713172804298

测试数据共享

1
2
3
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

image-20230713172818313

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

1
2
3
4
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 语法的格式是非常重要的,缩进也要得当。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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

image-20230713172833841

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

depends_on

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

1
2
3
4
5
6
7
8
9
10
11
version: '3'
services:
web:
build: .
depends_on:
- db
- redis
redis:
image: redis
db:
image: postgres

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

volumes

挂载数据卷

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

volumes_from

挂载数据卷容器

1
2
3
volumes_from:
- service_name
- container_name

links

链接到其它服务中的容器。在 Redis 搭建主从架构时我便使用到了它。

1
2
3
4
links:
- db
- db:database
- redis

build

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

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

1
build: /path/to/build/dir

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

1
build: ./dir

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

1
2
3
build:
context: ../
dockerfile: path/of/Dockerfile

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

实际操作案例

内网镜像拉取

​ 很多时候,我们只有内网环境,没有外网环境,不能方便的拉取镜像文件,这个时候我们可以借助外网环境将镜像拉取下来然后再拷贝到内网环境中去。

​ 外网环境拉取你想要的镜像文件,以jdk:8为案例:

1
2
3
4
5
拉取镜像
docker pull openjdk:8
将镜像当成tar包 下面两种方式都是可以的 标签/或者imageId(这个就直接复制你pull下来的那个messageId就行了)
docker save -o openjdk8.tar openjdk:8
docker save -o openjdk8.tar imageId

openjdk8.tar这个文件会在你打包的当前目录下面存在的,你在什么目录下面打包,他就在哪个目录下。

然后将这个tar包下载下来,放到内网环境的服务器上,内网服务器安装docker就不赘述了。然后执行:

1
docker load -i openjdk8.tar

这样就可以了,然后通过下面命令查看有没有执行成功:

1
docker images

找到对应的标签就说明执行成功了。这就完成了一个外网环境将镜像迁移到内网环境中去的操作。

编写Dockerfile

此时我们已经拥有了,基础镜像文件,我们要将这个镜像文件打包成我们需要的镜像文件,也就是将我们的Java程序丢进去。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
FROM openjdk:8
# 工作目录
WORKDIR /opt/javaapps/pis-ats-interface

# 复制配置文件到容器中
COPY application.yml /opt/javaapps/pis-ats-interface/

# 复制 Jar 文件到容器的对应目录中去
COPY app.jar /opt/javaapps/pis-ats-interface/

# 暴露容器的端口
EXPOSE 9889

# 指定运行 Jar 文件的命令
CMD ["java", "-jar", "/opt/javaapps/pis-ats-interface/app.jar", "--spring.config.name=application", "--server.port=9889","&"]

简单的Dockerfile就完成了,此时我们需要将Dockerfile重新构建成一份新的镜像文件

构建成镜像文件

1
2
3
4
5
# 语法如下
docker build -t <镜像名称> <Dockerfile路径>
# 实例 java8是我对镜像的命名 .表示在当前目录下 下面一个是表示含有具体目录 不需要将Dockerfile文件写出 他默认找这个文件的
docker build -t java8 .
docker build -t java8 /opt/javaapps/pis-ats-interface/

此时已经自定义完成了一个新的镜像文件 java8,有了镜像就需要去创建一个新的容器了,由于我们是要运行我们的java项目,那么肯定是需要将端口映射到主机外部的,所以我们启动的时候则需要开放出端口来。

1
2
3
4
# 语法  将9889的内部端口映射到外部端口 8888 中去
docker run -d --name my-container -p 8888:9889 my-image
# 实例 这里我是创建了一个java8的镜像创建了一个java8的容器,并且是后台运行的,在将9889端口映射到9889端口上去
docker run -d --name java8 -p 9889:9889 java8

至此就完成了一个服务的运行。

服务运行起来了,我们就需要查看日志,就需要进入到内部容器中去(此时我还没有做挂载数据卷的操作)。

1
2
3
4
5
# 语法 
docker exec -it my-app-container bash
# 实例 我的容器名称是java8
docker exec -it java8 bash
# 然后就可以进入到文件目录查看自己系统产生的日志文件了 这个根据你的log4j或者其他框架 看你的文件具体产生在哪

还有一点就是docker也会产生日志文件的,我们系统产生的日志会由 Docker 守护进程捕获并记录到宿主机的日志系统中。所以我们可以直接查看docker的日志,从而去看我们系统上的日志。

1
2
3
4
# 语法
docker logs 容器名称
# 实例
docker logs java8

那么问题就出现了,这样docker的日志就会越来越多,我们在系统会有限制日志的产生,但docker本身不会呀,所以我们就需要去限制docker的日志量。

1
2
3
4
5
6
7
8
9
10
# 修改docker配置
vi /etc/docker/daemon.json
# 添加如下信息
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file":"3"
}
}

提示:添加之后仅对后面创建的容器生效,对之前的容器并不生效,所以需要删了之前的容器,重新创建。

从上面的操作就能看出这样启动一个程序效率低下,而且不能主动的去内外端口映射,十分麻烦,所以我们就需要安装docker compose。

外网操作的相关已经在之前的进行相应的表述。接下来学习内网的操作。

Docker Compose的实战应用

离线安装:

1
https://github.com/docker/compose/releases/download/v2.2.2/docker-compose-linux-x86_64

将下载的文件传到内网服务器上 目录自己决定

1
2
3
sudo mv docker-compose-Linux-x86_64 /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
docker-compose -v

这就完成了安装了,版本内容就自己看。接下来就是编写docker-compose.yml文件。

我们可以使用镜像进行编写yml文件,也可以直接使用Dockerfile进行编写yml文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
version: '3'

services:
# 在docker-compose命令中需要用到这个名称
java8:
# 使用镜像文件进行编写yml 这是我自己构建的一个镜像文件
image: java8
ports:
# 开放映射端口
- 9889:9889
- 7667:7667
# 容器名称 这个是根据你自己想给你的服务取什么名字的
container_name: java8
# 当遇到了出现崩溃错误的时候会自动重启
restart: always
# 挂载数据卷 将容器内的/var/log/pis-ats-interface 挂载到宿主机/opt/datas/atslog中去
volumes:
- /opt/datas/atslog:/var/log/pis-ats-interface

这样一个简单的docker-compose.yml就写完了,然后需要注意的是,这个文件在哪目录下,哪个目录才能执行相应的命令。

比如我在 /opt/java目录下 有docker-compose.yml文件 我只能在这个目录下才能运行docker-compose up -d命令, -d是表示后台运行。

下面是一些相关命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# 执行启动程序
docker-compose up -d

# 启动已存在但停止的所有service 前提是这个容器已经存在 所以才有这个服务
docker-compose start [serviceName]

# 停止运行的service , serviceName(可选):表示停止某一个service
docker-compose stop [serviceName]

# :删除已停止的所有service -f :删除不在询问 (可选)serviceName:表示删除已停止某一个service
docker-compose rm -f [serviceName]

# 执行关闭程序
docker-compose down

# -v :删除挂载卷和volunme的链接
* docker-compose down -v

# 查看服务内所有容器日志输出,加上serviceName表示输出某一个service的日志
* docker-compose logs [serviceName]

# 实时输出日志
docker-compose run service command

# 实例 java8 是我的服务名称 后面的是容器内产生的日志路径文件
docker-compose run java8 tail -f /opt/ats/ats-info.log

# 进入到某个容器
docker-compose exec [serviceName] sh

# 重启服务
docker-compose restart [serviceName]

# 验证和查看compose文件
docker-compose config

# 列出所用的镜像
docker-compose images

# 设置服务个数 Eg:docker-compose scale web=2 worker=3
docker-cpmpose scale

# 暂停服务
docker-compose pause [serviceName]

# 恢复服务
docker-compose unpause [serviceName]

环境变量设置

上面提到我们每次只能在有docker-compose.yml文件的目录下才能使用docker-compose的相关命令,这样就很麻烦,所以需要去配置下所谓的环境变量。通过设置 alias 别名(环境变量)来实现 docker-compose 命令在任意路径下可执行。

Linux 中 alias 命令用来设置指令的别名,通常用于对一些较长的命令进行简化。它的语法格式为:

1
alias [别名]='原命令 -选项/参数'

例如:

1
alias ll='ls -lt'

那么让 docker-compose 命令在任意路径下都能使用的设置方法如下: vim ~/.bashrc,加入一行:

1
alias docker-compose='cd /data/soft/harbor;docker-compose'

保存退出,执行:

1
source ~/.bashrc

查看已经设置的别名列表,此时能看到 docker-compose 已经设置,然后就可以在任何目录下都能运行docker-compose命令了。

多个服务运行

docker-compose运行单个服务的规则已经讲完,现在就要运行多个服务的了,一般运行多个服务,我们肯定需要一些环境,比如MySQL、Redis、消息中间件(eg:RabbitMq)、注册中心(Nacos)等。所以就需要之前提及到的知识点。depends_on来解决容器的依赖、启动先后的问题

比如下面的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
version: '3'

services:
mysql:
image: mysql
ports:
- 3306:3306
environment:
- MYSQL_ROOT_PASSWORD=123456
volumes:
- ./mysql_data:/var/lib/mysql
- ./mysql_logs:/var/log/mysql

redis:
image: redis
ports:
- 6379:6379
environment:
- REDIS_PASSWORD=123456
volumes:
- ./redis_data:/data
- ./redis_logs:/var/log/redis

rabbitmq:
image: rabbitmq
ports:
- 5672:5672
- 15672:15672
environment:
- RABBITMQ_DEFAULT_USER=guest
- RABBITMQ_DEFAULT_PASS=guest
volumes:
- ./rabbitmq_data:/var/lib/rabbitmq
- ./rabbitmq_logs:/var/log/rabbitmq

nacos:
image: nacos/nacos-server
ports:
- 8848:8848
environment:
- MODE=standalone
- SPRING_DATASOURCE_PLATFORM=mysql
- MYSQL_SERVICE_HOST=mysql
- MYSQL_SERVICE_PORT=3306
- MYSQL_SERVICE_DB_NAME=nacos
- MYSQL_SERVICE_USERNAME=root
- MYSQL_SERVICE_PASSWORD=123456
volumes:
- ./nacos_data:/home/nacos/data
- ./nacos_logs:/var/log/nacos

java9:
image: java9
ports:
- 9887:9887
depends_on:
- mysql
- redis
- rabbitmq
- nacos

java10:
image: java10
ports:
- 9888:9888
depends_on:
- mysql
- redis
- rabbitmq
- nacos

具名挂载方式:

image-20230712221940580

匿名挂载方式:

image-20230712222425432

这是两种挂载的方式,建议推荐使用上面的一个。

tips:一般如果权限不足可以加上root用户上去,如下,在jenkins上就使用了root用户。
“root”是指使用Jenkins的根用户。这意味着具有根权限的用户正在执行或配置Jenkins的相关操作。通常情况下,根用户具有系统的最高权限,并且可以执行各种特权操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
version: '3'

services:
java8:
image: java8
ports:
- 9889:9889
- 7667:7667
container_name: java8
restart: always
volumes:
- /opt/datas/atslog:/var/log/pis-ats-interface:rw,delegated,size=200kb
jenkins:
user: root
image: jenkins/jenkins:lts
ports:
- 8999:8080
container_name: jenkins
restart: always
volumes:
- /opt/datas/jenkins/home:/var/jenkins_home
- /opt/datas/jenkins/log:/var/log/jenkins