目录
制作镜像方法2:使用Dockerfile构建新镜像... 25
Docker简介
什么是Docker?
Docker 是世界领先的软件容器平台。开发人员利用 Docker 可以消除协作编码时“在我的机器上可正常工作”的问题。运维人员利用 Docker 可以在隔离容器中并行运行和管理应用,获得更好的计算密度。企业利用 Docker 可以构建敏捷的软件交付管道,以更快的速度、更高的安全性和可靠的信誉为 Linux 和 Windows Server 应用发布新功能。
Docker 属于 Linux 容器的一种封装,提供简单易用的容器使用接口。它是目前最流行的 Linux 容器解决方案。Docker 将应用程序与该程序的依赖,打包在一个文件里面。运行这个文件,就会生成一个虚拟容器。程序在这个虚拟容器里运行,就好像在真实的物理机上运行一样。有了 Docker,就不用担心环境问题。
总体来说,Docker 的接口相当简单,用户可以方便地创建和使用容器,把自己的应用放入容器。容器还可以进行版本管理、复制、分享、修改,就像管理普通的代码一样。
Dokcer 分为 EE 和 CE 两个版本;CE 社区版【免费】,由社区维护提供技术支持,应用场景适合个人开发和小团队使用。EE 企业版【收费】,有技术团队和售后团队提供技术支持,应用场景适合企业开发,EE 版的功能要比 CE 多,且更加安全
为什么要使用Docker
容器除了运行其中应用外,基本不消耗额外的系统资源,使得应用的性能很高,同时系统的开销尽量小。
传统虚拟机方式运行 10 个不同的应用就要起 10 个虚拟机,而Docker 只需要启动 10 个隔离的应用即可。
具体说来,Docker 在如下几个方面具有较大的优势:
1、更快速的交付和部署
对开发和运维(devop)人员来说,最希望的就是一次创建或配置,可以在任意地方正常运行。
开发者可以使用一个标准的镜像来构建一套开发容器,开发完成之后,运维人员可以直接使用这个容器来部署代码。
Docker 可以快速创建容器,快速迭代应用程序,并让整个过程全程可见,使团队中的其他成员更容易理解应用程序是如何创建和工作的。
Docker 容器很轻很快!容器的启动时间是秒级的,大量地节约开发、测试、部署的时间。
2、更高效的虚拟化
Docker 容器的运行不需要额外的 hypervisor 支持,它是内核级的虚拟化,因此可以实现更高的性能和效率。
3、更轻松的迁移和扩展
Docker 容器几乎可以在任意的平台上运行,包括物理机、虚拟机、公有云、私有云、个人电脑、服务器等。 这种兼容性可以让用户把一个应用程序从一个平台直接迁移到另外一个。
4、更简单的管理
使用 Docker,只需要小小的修改,就可以替代以往大量的更新工作。所有的修改都以增量的方式被分发和更新,从而实现自动化并且高效的管理。
从下图可以看出,VM是一个运行在宿主机之上的完整的操作系统,VM运行自身操作系统会占用较多的CPU、内存、硬盘资源。Docker不同于VM,只包含应用程序以及依赖库,基于libcontainer运行在宿主机上,并处于一个隔离的环境中,这使得Docker更加轻量高效,启动容器只需几秒钟之内完成。由于Docker轻量、资源占用少,使得Docker可以轻易的应用到构建标准化的应用中。
但Docker目前还不够完善,比如隔离效果不如VM,共享宿主机操作系统的一些基础库等;网络配置功能相对简单,主要以桥接方式为主;查看日志也不够方便灵活。
Docker 在容器的基础上,进行了进一步的封装,从文件系统、网络互联到进程隔离等等,极大的简化了容器的创建和维护。使得 Docker 技术比虚拟机技术更为轻便、快捷。
作为一种新兴的虚拟化方式,Docker 跟传统的虚拟化方式相比具有众多的优势。Docker 容器的启动可以在秒级实现,这相比传统的虚拟机方式要快得多;Docker 对系统资源的利用率很高,一台主机上可以同时运行数千个 Docker 容器。
Docker的相关概念
Docker是CS架构,主要有两个概念
- Docker daemon: 运行在宿主机上,Docker守护进程,用户通过Docker client(Docker命令)与Docker daemon交互
- Docker client: Docker 命令行工具,是用户使用Docker的主要方式,Docker client与Docker daemon通信并将结果返回给用户,Docker client也可以通过socket或者RESTful api访问远程的Docker daemon
Docker的三个主要概念
- 镜像(Docker image):镜像是只读的,镜像中包含有需要运行的文件。镜像用来创建container,一个镜像可以运行多个container;镜像可以通过Dockerfile创建,也可以从Docker hub/registry上下载。
- 容器(Docker container):容器是Docker的运行组件,启动一个镜像就是一个容器,容器是一个隔离环境,多个容器之间不会相互影响,保证容器中的程序运行在一个相对安全的环境中。
- 仓库(Docker hub/registry): 共享和管理Docker镜像,用户可以上传或者下载上面的镜像。
Docker 仓库是用来包含镜像的位置,Docker提供一个注册服务器(Register)来保存多个仓库,每个仓库又可以包含多个具备不同Tag的镜像。
Docker运行中使用的默认仓库是 Docker Hub 公共仓库。
Docker官方提供一个公共仓库,称为Docker Hub,官方地址为https://registry.hub.docker.com/,也可以搭建自己私有的Docker registry(私有仓库)。
简单来说, docker主要由 远程仓库(repository)、本地镜像(image)、本地容器(container)组成。
在使用 Docker 前,通常需要先从 Docker Hub(Docker 的公共镜像仓库)或者其他私有镜像仓库中拉取所需的镜像。
可以使用 docker pull 命令来拉取镜像,例如:docker pull nginx:latest
Docker镜像与容器的关系
Docker镜像与容器之间的关系可以理解为模板与实例的关系(容器是镜像的运行实例,而镜像是容器的模板)。
镜像是Docker生命周期中的构建或者打包阶段,而容器则是启动或者执行阶段。
镜像就相当于打包好的版本,镜像启动之后运行在容器中,仓库就是装存储镜像的地方。
总的来说,镜像是文件, 容器是进程。容器是基于镜像创建的,即容器中的进程依赖于镜像中的文件,这里的文件包括进程运行所需要的可执行文件、依赖软件、库文件、配置文件等等。
Docker基本使用过程为:远程镜像–下载 –> 本经镜像–运行 –> 本地容器。
为什么不建议把数据库部署在Docker容器内?
Docker不适合部署数据库的7大原因如下:
1、数据安全问题
不要将数据储存在容器中,这也是 Docker 官方容器使用技巧中的一条。容器随时可以停止、或者删除。当容器被rm掉,容器里的数据将会丢失。为了避免数据丢失,用户可以使用数据卷挂载来存储数据。但是容器的 Volumes 设计是围绕 Union FS 镜像层提供持久存储,数据安全缺乏保证。如果容器突然崩溃,数据库未正常关闭,可能会损坏数据。另外,容器里共享数据卷组,对物理机硬件损伤也比较大。
即使你要把 Docker 数据放在主机来存储 ,它依然不能保证不丢数据。Docker volumes 的设计围绕 Union FS 镜像层提供持久存储,但它仍然缺乏保证。
使用当前的存储驱动程序,Docker 仍然存在不可靠的风险。如果容器崩溃并数据库未正确关闭,则可能会损坏数据。
2、性能问题
大家都知道,MySQL 属于关系型数据库,对IO要求较高。当一台物理机跑多个时,IO就会累加,导致IO瓶颈,大大降低 MySQL 的读写性能。
在一次Docker应用的十大难点专场上,某国有银行的一位架构师也曾提出过:“数据库的性能瓶颈一般出现在IO上面,如果按 Docker 的思路,那么多个docker最终IO请求又会出现在存储上面。现在互联网的数据库多是share nothing的架构,可能这也是不考虑迁移到 Docker 的一个因素吧”。
针对性能问题有些同学可能也有相对应的方案来解决:
(1)数据库程序与数据分离
如果使用Docker 跑 MySQL,数据库程序与数据需要进行分离,将数据存放到共享存储,程序放到容器里。如果容器有异常或 MySQL 服务异常,自动启动一个全新的容器。另外,建议不要把数据存放到宿主机里,宿主机和容器共享卷组,对宿主机损坏的影响比较大。
(2)跑轻量级或分布式数据库
Docker 里部署轻量级或分布式数据库,Docker 本身就推荐服务挂掉,自动启动新容器,而不是继续重启容器服务。
(3)合理布局应用
对于IO要求比较高的应用或者服务,将数据库部署在物理机或者KVM中比较合适。目前TX云的TDSQL和阿里的Oceanbase都是直接部署在物理机器,而非Docker 。
3、网络问题
要理解 Docker 网络,您必须对网络虚拟化有深入的了解。也必须准备应付好意外情况。你可能需要在没有支持或没有额外工具的情况下,进行 bug 修复。
我们知道:数据库需要专用的和持久的吞吐量,以实现更高的负载。我们还知道容器是虚拟机管理程序和主机虚拟机背后的一个隔离层。然而网络对于数据库复制是至关重要的,其中需要主从数据库间 24/7 的稳定连接。未解决的 Docker 网络问题在1.9版本依然没有得到解决。
把这些问题放在一起,容器化使数据库容器很难管理。我知道你是一个顶级的工程师,什么问题都可以得到解决。但是,你需要花多少时间解决 Docker 网络问题?将数据库放在专用环境不会更好吗?节省时间来专注于真正重要的业务目标。
4、状态
在 Docker 中打包无状态服务是很酷的,可以实现编排容器并解决单点故障问题。但是数据库呢?将数据库放在同一个环境中,它将会是有状态的,并使系统故障的范围更大。下次您的应用程序实例或应用程序崩溃,可能会影响数据库。
5、资源隔离
资源隔离方面,Docker 确实不如虚拟机KVM,Docker是利用Cgroup实现资源限制的,只能限制资源消耗的最大值,而不能隔绝其他程序占用自己的资源。如果其他应用过渡占用物理机资源,将会影响容器里MySQL 的读写效率。
需要的隔离级别越多,获得的资源开销就越多。相比专用环境而言,容易水平伸缩是Docker的一大优势。然而在 Docker 中水平伸缩只能用于无状态计算服务,数据库并不适用。
我们没有看到任何针对数据库的隔离功能,那为什么我们应该把它放在容器中呢?
6、云平台的不适用性
大部分人通过共有云开始项目。云简化了虚拟机操作和替换的复杂性,因此不需要在夜间或周末没有人工作时间来测试新的硬件环境。当我们可以迅速启动一个实例的时候,为什么我们需要担心这个实例运行的环境?
这就是为什么我们向云提供商支付很多费用的原因。当我们为实例放置数据库容器时,上面说的这些便利性就不存在了。因为数据不匹配,新实例不会与现有的实例兼容,如果要限制实例使用单机服务,应该让 DB 使用非容器化环境,我们仅仅需要为计算服务层保留弹性扩展的能力。
7、运行数据库的环境需求
常看到 DBMS 容器和其他服务运行在同一主机上。然而这些服务对硬件要求是非常不同的。
数据库(特别是关系型数据库)对 IO 的要求较高。一般数据库引擎为了避免并发资源竞争而使用专用环境。如果将你的数据库放在容器中,那么将浪费你的项目的资源。因为你需要为该实例配置大量额外的资源。在公有云,当你需要 34G 内存时,你启动的实例却必须开 64G 内存。在实践中,这些资源并未完全使用。
怎么解决?您可以分层设计,并使用固定资源来启动不同层次的多个实例。水平伸缩总是比垂直伸缩更好。
总结
针对上面问题是不是说数据库一定不要部署在容器里吗?
答案是:并不是
我们可以把数据丢失不敏感的业务(搜索、埋点)就可以数据化,利用数据库分片来来增加实例数,从而增加吞吐量。
docker适合跑轻量级或分布式数据库,当docker服务挂掉,会自动启动新容器,而不是继续重启容器服务。
数据库利用中间件和容器化系统能够自动伸缩、容灾、切换、自带多个节点,也是可以进行容器化的。
Docker的安装及常用命令
安装Docker
-设置 yum 源:(以下两个源均可)
中央仓库:
yum-config-manager --add-repo http://download.docker.com/linux/centos/docker-ce.repo
阿里仓库:
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
-更新yum软件包索引
yum makecache fast
-选择docker版本并安装 :
(1)卸载旧版本(如果之前安装过的话):
yum remove docker docker-common docker-selinux docker-engine
(2)查看可用版本有哪些:
yum list docker-ce --showduplicates | sort -r
(3)选择版本并安装:
yum -y install docker-ce-18.03.1.ce
或者直接自动安装CE最新版:
# 安装docker相关的 docker-ce 社区版 而ee是企业版
yum install docker-ce docker-ce-cli containerd.io
(4)查看安装好的Docker版本:
docker version
查看Docker版本
docker version
查看Docker概要信息
docker info
查看Docker总体帮助文档
docker --help
查看Docker命令帮助文档
docker 具体命令 --help
启动Docker
systemctl start docker
设置Docker开机自启
systemctl enable docker
停止Docker
systemctl stop docker
重启Docker
systemctl restart docker
查看Docker状态
systemctl status docker
拉取镜像(以拉取Redis镜像为例)
docker pull 镜像名
# 查找镜像
docker search redis
# 下载镜像, 默认最新版本
docker pull redis:7.0.12
(注意:使用 docker search redis:7.0.12 是无法搜到镜像,好像默认就是只能搜索到 latest版本,但是使用 docker pull redis:7.0.12 是可以成功拉取镜像的。)
# 运行镜像到名为redis01的容器
docker run --name redis01 -d -p 6379:6379 redis:latest
或
docker run --name redis01 -d -p 6379:6379 redis:7.0.12
注意:第一次启动可用上面的命令,再次启动时,如果还希望用之前名为redis01的容器,需要使用如下命令启动:
docker start redis01
# 使用redis-cli测试
# 进入docker容器测试redis是否安装按成
# docker exec -it 容器id bashshell
docker exec -it redis01 /bin/bash
> redis-cli
> set a 10
> get a
# 停止容器
docker stop redis01
查找镜像
docker search [OPTIONS] 镜像名称
例如:
docker search redis
表头说明:
NAME:镜像名
DESCRIPTION:镜像说明
STARS:点赞数量
OFFICIAL:是否官方的
查看本机镜像
docker images [OPTIONS] [REPOSITORY[:TAG]]
该命令将列出当前系统上存在的所有 Docker 镜像,包括镜像的名称、版本号、创建时间和大小等信息。
表头说明:
REPOSITORY:表示镜像的仓库源
TAG:镜像的标签
IMAGE ID:镜像的ID
CREATED:镜像的创建时间
SIZE:镜像大小
同一个仓库源可以有多个TAG版本,代表这个仓库源的不同版本。我们使用REPOSITORY:TAG来定义不同的镜像。
PS:如果你不指定一个镜像的版本标签,例如你只是使用了ubuntu,那么docker将默认使用ubuntu: latest镜像。也就是在没有指定版本标签时候,默认会使用latest的。
删除镜像
docker rmi [OPTIONS] IMAGE [IMAGE...]
例如:
docker rmi fcc054f90308
PS:如果镜像被占用,可以使用强制删除参数-f:
docker rmi -f fcc054f90308
启动镜像
-docker run语法:
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
常见OPTIONS说明:
-docker run 执行流程:
首先在指定镜像上创建一个可写的容器层
然后使用指定的命令(COMMAND)启动它
docker run 相当于执行了两个 API:/containers/create、/containers/(id)/start
-第一次启动请使用以下命令启动镜像:
docker run -it <镜像名称>
其中,"-it" 参数表示通过交互式终端启动镜像,可以通过该终端与镜像进行交互操作。
例如,如果需要启动 Ubuntu 18.04 镜像,可以使用以下命令:
docker run -it ubuntu:18.04
除了使用镜像名称启动镜像,还可以使用镜像的 ID 启动,例如:
docker run -it <镜像 ID>
注意:
docker run 只在第一次运行时使用,将镜像放到容器中,以后再次启动这个容器时,只需要使用命令docker start即可。
例如:
docker run --name redis01 -d -p 6379:6379 redis:7.0.12
docker start redis01
参数说明:
--name:表示指定容器的名字。
-d:表示后台启动,不加-d是在前台启动。
-p:表示指定对内对外端口的映射,:左边是对外接口(宿主端口),:右边是对内接口(容器端口)。
redis:7.0.12:表示使用的镜像及版本。
PS:docker run相当于执行了两步操作:将镜像放入容器中(docker create),然后将容器启动,使之变成运行时容器(docker start)。
docker start的作用是,启动已存在的容器。也就是说,如果使用这个命令,我们必须事先知道这个容器的ID(CONTAINER ID),或者这个容器的名字(NAMES),我们可以使用docker ps找到这个容器的信息。
查看容器
列出所有正在运行的Docker容器及其详细信息:
docker ps
查看所有容器,包括未运行的容器及其详细信息:
docker ps -a
PS:可以使用“docker ps”命令来获取容器ID和容器名。
容器重命名
docker rename old_name new_name
启动容器
docker start [CONTAINER ID | NAMES]
请将[CONTAINER ID | NAMES]替换为要停止的容器的ID或容器名。
重启运行中的容器
docker restart [CONTAINER ID | NAMES]
进入容器
在启动容器后,可使用docker exec命令进入Docker容器。
语法:
docker exec [OPTIONS ] CONTAINER COMMAND [ARG.. .]
例如:
docker exec -it redis01 /bin/bash
可以在终端中执行各种命令,并查看镜像的具体配置和状态信息。
例如:
> redis-cli
> set a 10
> get a
退出容器
当完成对镜像的操作后,可以使用以下命令退出当前容器:
exit
停止容器
docker stop [CONTAINER ID | NAMES]
停止所有容器
docker ps -aq|xargs docker stop
强制停止容器
docker kill [CONTAINER ID | NAMES]
删除容器
如果您想从系统中完全删除容器,请使用以下命令:
docker rm [CONTAINER ID | NAMES]
注意:需要先停止容器才能删除容器。
停止并删除容器
docker ps -aq|xargs docker stop|xargs docker rm
查看容器日志
docker logs -tf [CONTAINER ID | NAMES]
docker logs --tail num [CONTAINER ID | NAMES] # num为要显示的日志条数
例如:
docker logs -tf redis01
docker logs -tf --tail 2 redis01
查看容器的元数据
docker inspect [CONTAINER ID | NAMES]
显示镜像或容器的详细信息
docker inspect CONTAINER | IMAGE [CONTAINER | IMAGE...]
制作镜像方法1:将容器打包成新的镜像
docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
-命令参数:
-a, --author="" 作者信息,"John Hannibal Smith <hannibal@a-team.com>"
-m, --message="" 提交信息
-p, --pause=true 在提交镜像时暂停容器
例子:
docker commit c3f279d17e0a Hyzhou/my_ubuntu:3.2.3
docker commit -a "Hyzhou<hyzhou@qq.com>" -m "addthe new software" c3f279d17e0a Hyzhou/my_ubuntu:3.2.3
制作镜像方法2:使用Dockerfile构建新镜像
Dockerfile 概念
Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。
镜像的定制实际上就是定制每一层所添加的配置、文件。
如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,那么之前提及的无法重复的问题、镜像构建透明性的问题、体积的问题就都会解决。这个脚本就是 Dockerfile。
Dockerfile 是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。
有了 Dockerfile,当我们需要定制自己额外的需求时,只需在 Dockerfile 上添加或者修改指令,重新生成 image 即可,省去了敲命令的麻烦。
构建命令:
docker build 命令会根据 Dockerfile 文件及上下文构建新 Docker 镜像:
docker build [OPTIONS] PATH|URL|-
-常见命令参数:
-f 指定Dockerfile文件, 如果不制定, 则使用当前目录下的 Dockerfile 文件, 当然也可以指定路径
-t,–tag 指定镜像名及标签,支持指定多个标签
Docker部署Jeecgboot
Redis构建及运行
#拉取镜像
docker pull redis:7.0.12
#启动镜像(第一次)
docker run --name redis01 -d -p 6379:6379 redis:7.0.12
#启动容器(除第一次外)
docker start redis01
#查看容器日志
docker logs -tf redis01
#进入Redis容器
docker exec -it redis01 /bin/bash
Jeecgboot前端构建及运行
前端Dockerfile的路径: ant-design-vue-jeecg\Dockerfile
(注意,实际构建时,我修改了Dockerfile文件的名字为Dockerfile-front,以便区分)
前端Dockerfile内容:
# docker镜像从nginx开始构建
FROM nginx
# 说明作者
MAINTAINER jeecgos@163.com
# 挂载docker镜像tmp目录到宿主机tmp目录
VOLUME /tmp
# 定义变量 LANG=en_US.UTF-8
ENV LANG en_US.UTF-8
# 运行命令, 将nginx配置覆盖写入到默认配置文件 && 创建静态资源目录(配置和资源目录需要对应起来)
# 这里修改了监听端口,并且修改后台接口地址为后端服务容器的名称。
RUN echo "server { \
listen 80; \
location ^~ /jeecg-boot { \
proxy_pass http://jeecgboot-server01:8099/jeecg-boot/; \
proxy_set_header Host jeecgboot-server01; \
proxy_set_header X-Real-IP \$remote_addr; \
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; \
} \
#解决Router(mode: 'history')模式下,刷新路由地址不能找到页面的问题 \
location / { \
root /var/www/html/; \
index index.html index.htm; \
if (!-e \$request_filename) { \
rewrite ^(.*)\$ /index.html?s=\$1 last; \
break; \
} \
} \
access_log /var/log/nginx/access.log ; \
} " > /etc/nginx/conf.d/default.conf \
&& mkdir -p /var/www \
&& mkdir -p /var/www/html
# 将宿主机dist/内容添加到镜像/var/www/html/下
ADD dist/ /var/www/html/
# 暴露端口 80和443
EXPOSE 80
EXPOSE 443
前端index.html修改:
构建及运行命令:
#构建镜像
docker build -f Dockerfile-front -t jeecgboot-front:0.0.1 .
#启动镜像(第一次)
docker run --name=jeecgboot-front01 -d -p 80:80 --link jeecgboot-server01 jeecgboot-front:0.0.1
#启动容器(除第一次外)
docker start jeecgboot-front01
#查看前台日志
docker logs -tf jeecgboot-front01
#进入前台容器
docker exec -it jeecgboot-front01/bin/bash
Jeecgboot后端构建及运行
后端Dockerfile的路径:jeecg-boot\jeecg-boot-module-system\Dockerfile
(注意,实际构建时,我修改了Dockerfile文件的名字为Dockerfile-back,以便区分)
后端Dockerfile内容:
# 指定打包基础 anapsix/alpine-java:8_server-jre_unlimited是一个Java8环境
FROM anapsix/alpine-java:8_server-jre_unlimited
# 说明作者
MAINTAINER jeecgos@163.com
# 创建镜像时执行命令
# 文件夹软连接
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
# 创建项目文件目录
RUN mkdir -p /jeecg-boot
# 指定工作区, 即容器默认在此目录运行
WORKDIR /jeecg-boot
# docker activiti 流程图中文乱码处理
# 将字体simsun.ttc 放到docker镜像的/usr/share/fonts目录下
COPY simsun.ttc /usr/share/fonts/simsun.ttc
#安装字体软件,完成字体配置
RUN apk add --update ttf-dejavu fontconfig && rm -rf /var/cache/apk/*
# 暴露端口
EXPOSE 8099
# 将jar包添加到镜像中
ADD ./target/jeecg-boot-module-system-2.2.1.jar ./
# 容器运行时执行命令
# 停顿60s 启动项目
CMD sleep 60;java -Djava.security.egd=file:/dev/./urandom -jar jeecg-boot-module-system-2.2.1.jar
JeecgBoot后端配置文件修改:
(注意:后端需要连接Redis,这里直接用Redis的容器名来连接的。MySQL我没用Docker构建,所以没有替换数据库的地哦)
构建及运行命令:
#构建镜像
docker build -f Dockerfile-back -t jeecgboot-server:0.0.1 .
#启动镜像(第一次)
docker run --name=jeecgboot-server01 -d -p 8099:8099 --link redis01 jeecgboot-server:0.0.1
#启动容器(除第一次外)
docker start jeecgboot-server01
#查看后台日志
docker logs -tf jeecgboot-server01
#进入后台容器
docker exec -it jeecgboot-server01 /bin/bash
Activiti流程图中文乱码问题解决
由于后端使用了alpine linux的带jdk8的镜像来制作的,所以中文处理方式和之前有所不同,具体处理步骤如下:
- 修改后端Dockerfile文件,添加如下字体拷贝命令及安装字体命令
(PS:需要将simsun.ttc和Dockerfile文件放在同一目录):
。。。。。。
# docker activiti 流程图中文乱码处理
# 将字体simsun.ttc 放到docker镜像的/usr/share/fonts目录下
COPY simsun.ttc /usr/share/fonts/simsun.ttc
#安装字体软件,完成字体配置
RUN apk add --update ttf-dejavu fontconfig && rm -rf /var/cache/apk/*
。。。。。。
- 重新构建后端镜像并运行:
docker build -f Dockerfile-back -t jeecgboot-server:0.0.1 .
docker run --name=jeecgboot-server01 -d -p 8099:8099 --link redis01 jeecgboot-server:0.0.1
Docker容器互联的两种方式
从上面Jeecgboot构建及运行的示例可知, docker内部可以通过 --link [container]的方式实现访问, 而自定义docker网络则是更好的互相访问方法。
(上面启动容器的时候我们通过--link映射了端口到宿主机, 实际上除了前端服务外, 其他容器并不需要向外提供服务, 完全不用映射端口。)
使用--link
在Docker中,--link参数用于将一个容器链接到另一个容器。这使得两个容器可以相互通信,而不需要暴露它们的端口给外部网络。
docker run --name=jeecgboot-server01 -d -p 8099:8099 --link redis01 jeecgboot-server:0.0.1
或
docker run --name=jeecgboot-front01 -d -p 80:80 --link jeecgboot-server01 jeecgboot-front:0.0.1
使用--network(定义Docker网络)
Docker网络是Docker容器之间和容器与外部网络之间的通信和连接的一种机制。
在Docker中,每个容器都可以有自己的网络栈,包括网络接口、IP地址和网络配置。Docker网络提供了一种灵活且可定制的方式,使得容器之间可以相互通信,并与主机或其他网络资源进行交互。
在docker中,重启后ip是会变的;docker默认采用bridge连接,启动容器的时候会按照顺序来获取对应ip地址,这就导致容器每次重启后ip都会发生变化。
也就是说容器间使用ip地址来进行通信的话,一旦有容器重启,重启的容器将不再能被访问到。 Docker 网络就能够解决这个问题。
Docker网络作用:容器之间的互联以及端口映射,容器IP变动的时候可以通过服务名直接网络通信而不受影响。
(PS:Docker run时不指定网络其实使用的是默认网络。)
Docker的默认网络但是默认不能直接通过容器名访问互联, 必须使用--link指定, 当然我们可以自定义一个网络来实现。
创建一个自定义网络命令如下:
docker network create [option] [net name]
–driver 驱动, 默认使用bridge即可
–subnet 子网范围
–gateway 网关
# 查看现有网络
docker network ls
# 新增网络
docker network create -d bridge my-net
# 运行容器并连接到新建的 my-net 网络【Jeecgboot】
docker run -d --network my-net --name redis01 redis:7.0.12
docker run -d --network my-net --name jeecgboot-server01 jeecgboot-server:0.0.1
docker run -d --network my-net --name jeecgboot-front01 -p 80:80 jeecgboot-front:0.0.1
# 移除网络
docker network rm my-net
# 查看网络内部信息
docker network inspect my-net
Docker Compose工具
Docker Compose简介
Docker Compose项目是Docker官方的开源项目,负责实现对Docker容器集群的快速编排,是用于定义和运行多容器 Docker 应用程序的工具。
通过 Compose,您可以使用 YML 文件来配置应用程序需要的所有服务。然后,使用一个命令,就可以从 YML 文件配置中创建并启动所有服务。
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来进行编排管理。
Compose安装
方式一:yum命令安装
yum -y install epel-release
yum -y install python-pip
yum -y install docker-compose
# 查看安装的版本
docker-compose -v
方式二:二进制文件安装
1.下载二进制文件:
https://github.com/docker/compose/releases
这里以2.24.6为例:
2.重命名二进制文件为docker-compose
3.上传至服务器 /usr/bin 目录
4.授权:
chmod +x /usr/local/bin/docker-compose
-查看版本:
docker-compose --version
Compose 使用的三个步骤
- 使用 Dockerfile 定义应用程序的环境。
- 使用 docker-compose.yml 定义构成应用程序的服务,这样它们可以在隔离环境中一起运行。
- 最后,执行 docker-compose up 命令来启动并运行整个应用程序。
JeecgBoot运行实例
由上面示例可知, JeecgBoot项目运行至少涉及三个镜像,如果要做负载均衡或者数据库集群则会更多, 一一启动太麻烦,使用docker-compose可以批量启动:
- 创建Redis,JeecgBoot前端、JeecgBoog后端镜像
- 修改docker-compose.yml内容:
docker-compose.yml的路径: jeecg-boot\docker-compose.yml
注意:如果你使用Docker 1.13以上版本,需要将docker-compose.yml中的version: '2'修改为version: '2.1',否则会提示如下错误:
ERROR: client version 1.22 is too old. Minimum supported API version is 1.24, please upgrade your client to a newer version
docker-compose.yml内容:
version: '2.1'
services:
redis:
image: redis:7.0.12
ports:
- 6379:6379
restart: always
container_name: redis01
jeecgboot-server:
image: jeecgboot-server:0.0.1
restart: always
container_name: jeecgboot-server01
ports:
- 8099:8099
links:
- redis
depends_on:
- redis
jeecgboot-front:
image: jeecgboot-front:0.0.1
restart: always
container_name: jeecgboot-front01
ports:
- 80:80
# 增加容器访问link
links:
# 此处关联的是本文件中服务的名字
- jeecgboot-server
# 增加关联配置, 前端依赖后端server
depends_on:
- jeecgboot-server
- 执行 docker-compose
(在docker-compose.yml同一目录下执行):
docker-compose up -d
注意:
因为是重新由Compose创建了容器,所以之前后端的Activiti中文字体处理可能失效了,需要在启动起来后端容器后,进入容器手动执行下:
apk add --update ttf-dejavu fontconfig && rm -rf /var/cache/apk/*
参考资料
http://www.ityouknow.com/docker.html
https://blog.youkuaiyun.com/Lee_0220/article/details/121335134
https://blog.youkuaiyun.com/a772304419/article/details/131502770
https://blog.youkuaiyun.com/m0_62436868/article/details/134355813
http://www.ityouknow.com/docker/2018/03/12/docker-use-dockerfile.html
http://www.ityouknow.com/docker/2018/03/15/docker-dockerfile-command-introduction.html
https://www.runoob.com/docker/docker-dockerfile.html
https://www.cnblogs.com/minseo/p/11548177.html
https://mp.weixin.qq.com/s/TZ5yyOsdguLK1xXhSfcYSw