初识 Docker 项目部署的问题 微服务虽然具备各种各样的优势,但服务的拆分通用给部署带来了很大的麻烦
分布式系统中,依赖的组件非常多,不同组件之间部署时往往会产生一些冲突
在数百上千台服务中重复部署,环境不一定一致,会遇到各种问题
Docker 解决依赖兼容问题 Docker 如何解决依赖的兼容问题的呢 ,采用了两个手段:
将应用的 Libs(函数库)、Deps(依赖)、配置与应用一起 打包
将每个应用放到一个 隔离 容器去运行,避免互相干扰
这样打包好的应用包中,既包含应用本身,也保护应用所需要的 Libs、Deps,无需再操作系统上安装这些,自然就不存在不同应用之间的兼容问题了
Docker 解决操作系统环境差异 虽然解决了不同应用的兼容问题,但是开发、测试等环境会存在差异,操作系统版本也会有差异,怎么解决这些问题呢?
计算机硬件:例如 CPU、内存、磁盘等
系统内核(内核与硬件交互,提供操作硬件指令):所有 Linux 发行版的内核都是 Linux,例如 CentOS、Ubuntu、Fedora 等。内核可以与计算机硬件交互,对外提供 内核指令 ,用于操作计算机硬件
系统应用(系统应用封装内核指令为函数,便于程序员调用):操作系统本身提供的应用、函数库。这些函数库是对内核指令的封装,使用更加方便
Ubuntu 和 CentOS 都是基于 Linux 内核,无非是系统应用不同,提供的函数库有差异。此时,如果将一个 Ubuntu 版本的 MySQL 应用安装到 CentOS 系统,MySQL 在调用 Ubuntu 函数库时,会发现找不到或者不匹配,就会报错了,那 Docker 如何解决不同系统环境问题的呢 ?
Docker 将用户程序与所需要调用的系统 (比如 Ubuntu) 函数库一起打包
Docker 运行到不同操作系统时,直接基于打包的函数库,借助于操作系统的 Linux 内核来运行
那么就可以认为 Docer 打包好的程序包可以应用在任何 Linux 内核的操作系统上
总结 Docker 是一个快速交付应用、运行应用的技术,具备下列优势:
可以将程序及其依赖、运行环境一起打包为一个镜像,可以迁移到任意 Linux 操作系统
运行时利用沙箱机制形成隔离容器,各个应用互不干扰
启动、移除都可以通过一行命令完成,方便快捷
Docker 架构 镜像和容器
镜像(Image,硬盘中的文件):Docker 将应用程序及其所需的依赖、函数库、环境、配置等文件打包在一起,称为镜像
容器(Container,相当于进程):镜像中的应用程序运行后形成的进程就是容器,只是 Docker 会给容器进程做隔离,对外不可见
镜像都是只读的 ,这样可以防止容器对镜像数据的写入,造成数据污染;如果容器需要写数据,可以从镜像中拷贝一份数据到自己的空间中,在本空间中进行读写操作
DockerHub DockerHub 是一个官方的 Docker 镜像的托管平台。这样的平台称为 Docker Registry,国内也有类似于 DockerHub 的公开服务,比如 网易云镜像服务 、阿里云镜像库 等
我们一方面可以将自己的镜像共享到 DockerHub,另一方面也可以从 DockerHub 拉取镜像
Docker 架构 Docker 是一个 CS 架构的程序,由两部分组成
服务端 (server):Docker 守护进程,负责处理 Docker 指令,管理镜像、容器等
客户端 (client):通过命令或 RestAPI 向 Docker 服务端发送指令。可以在本地或远程向服务端发送指令
安装 Docker Docker 分为 CE 和 EE 两大版本。CE 即社区版(免费,支持周期 7 个月),EE 即企业版,强调安全,付费使用,支持周期 24 个月。这里主要介绍 CentOS 安装 Docker
1.1、卸载(可选)
如果之前安装过旧版本的 Docker,可以使用下面命令卸载
1 2 3 4 5 6 7 8 9 10 11 yum remove docker \ docker-client \ docker-client-latest \ docker-common \ docker-latest \ docker-latest-logrotate \ docker-logrotate \ docker-selinux \ docker-engine-selinux \ docker-engine \ docker-ce
\
表示命令没有结束还需要继续往下读(换行),命令太长可以通过 \
提高可读性
1.2、安装 yum-utils 工具
1 2 3 yum install -y yum-utils \ device-mapper-persistent-data \ lvm2 --skip-broken
1.3、设置下载的镜像源
1 2 3 4 5 6 7 yum-config-manager \ --add-repo \ https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo sed -i 's/download.docker.com/mirrors.aliyun.com\/docker-ce/g' /etc/yum.repos.d/docker-ce.repo yum makecache fast
1.4、安装 docker
1 yum install -y docker-ce
至此 docker 安装完毕
启动 docker Docker 应用需要用到各种端口,逐一去修改防火墙设置。非常麻烦,因此建议大家直接关闭防火墙。启动 docker 前,一定要关闭防火墙!
1、关闭防火墙
1 2 3 4 5 6 # 关闭防火墙 systemctl stop firewalld # 禁止开机启动防火墙 systemctl disable firewalld # 查看防火墙状态 systemctl status firewalld
2、启动 Docker
1 2 3 4 5 systemctl start docker # 启动docker服务 systemctl stop docker # 停止docker服务 systemctl restart docker # 重启docker服务
3、可通过查看 Docker 状态或 Docker 版本查看是否已经启动
1 2 3 systemctl status docker docker -v
配置镜像 docker 官方镜像仓库网速较差,我们需要设置国内镜像服务,可参考阿里云的镜像加速文档:https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors
1 2 3 4 5 6 7 8 9 10 11 sudo mkdir -p /etc/docker //将内容写入json文件中 sudo tee /etc/docker/daemon.json <<-'EOF' { "registry-mirrors" : ["https://5vycoa8o.mirror.aliyuncs.com" ] } EOF sudo systemctl daemon-reload sudo systemctl restart docker
Docker 基本操作 镜像操作 镜像名称 镜名称一般分两部分组成:[repository]:[tag]
,在没有指定 tag 时,默认是 latest,代表最新版本的镜像。如这里的 mysql 就是 repository,5.7 就是 tag,合一起就是镜像名称,代表 5.7 版本的 MySQL 镜像
镜像命令 常见的镜像操作命令如图
从镜像服务器拉去镜像:docker pull
从本地文件构建镜像:docker build
查看本地存在哪些镜像:docker images
删除本地镜像:docker rmi
推送镜像到镜像服务器:docker push
将镜像打包成一个压缩包:docker save
加载压缩包为镜像:docker load
查看 docker 帮助文档
1 2 3 4 docker --help docker images --help
案例:从 DockerHub 中拉取镜像 需求:从 DockerHub 中拉取一个 nginx 镜像并查看
1、首先去镜像仓库搜索 nginx 镜像,比如 Docker Hub Container Image Library | App Containerization
2、查看镜像
可以查看到本地中已经有 Nginx 镜像了
1 2 3 [root@localhost ~] REPOSITORY TAG IMAGE ID CREATED SIZE nginx latest 605c77e624dd 12 months ago 141MB
案例:通过压缩包导出导入镜像 需求:利用 docker save 将 nginx 镜像导出磁盘,然后再通过 load 加载回来
1、利用 docker xx –help 命令查看 docker save 和 docker load 的语法
通过帮助文档可得知 save 的命令格式为:
1 docker save -o [保存的目标文件名称] [镜像名称]
2、使用 docker save 导出镜像到磁盘
1 docker save -o nginx.tar nginx:latest
-o
表示选项,注意此时镜像在本地还是有的
3、使用 docker load 加载镜像
3.1)先删除本地的 nginx 镜像
3.2)加载压缩包镜像
1 docker load -i nginx.tar
容器操作 容器相关命令
容器有三个状态:
运行:进程正常运行
暂停:进程暂停,CPU 不再运行,并不释放内存
停止:进程终止,回收进程占用的内存、CPU 等资源
容器操作的命令:
docker run:创建并运行一个容器,处于运行状态
docker pause:让一个运行的容器暂停
docker unpause:让一个容器从暂停状态恢复运行
docker stop:停止一个运行的容器
docker start:让一个停止的容器再次运行
docker rm:删除一个容器
docker ps:查看所有运行的容器及状态
docker logs:查看容器运行日志
docker exec:进入容器执行命令
案例:创建运行一个容器 需求:创建并运行 nginx 容器的命令
可以去官网搜索 Nginx,并查看其文档:nginx - Official Image | Docker Hub ,比如官网中给了如下运行命令示例:
1 docker run --name some-nginx -d -p 8080:80 some-content-nginx
这里以如下命令进行命令解读:
1 docker run --name containerName -p 80 :80 -d nginx
docker run :创建并运行一个容器
–name : 给容器起一个名字,比如叫做 mn
-p :将宿主机端口与容器端口映射,冒号左侧是宿主机端口,右侧是容器端口;此处宿主机端口不做要求,但容器端口基本上取决于容器本身(软件监听的端口可能就是某一个端口)
-d:后台运行容器
nginx:镜像名称,例如 nginx,没有写标签 tag 说明是最新版 latest
![[Pasted image 20230110202450.png]]
因为容器是隔离的,所以用户无法直接通过 80 端口来访问到容器,需要将容器的端口与宿主机端口映射。端口映射就相当于将原本隔离的容器暴露出一个小窗口,通过这个小窗口来对容器进行访问
容器创建完成后,会生成一个唯一 ID
1 2 [root@localhost ~]# docker run --name mn -p 80:80 -d nginx b8ae9bcbdde97a1ef9b055e44470427cd937571c4f2fdb5cb7a710c3d9a828e7
通过访问宿主机 80 端口,就可访问 docker 中的 Nginx 服务了
通过 logs 命令可以查看容器日志
1 2 3 4 5 6 7 8 docker logs [OPTIONS] CONTAINER docker logs mn docker logs -f mn
案例:操作容器 需求:进入 Nginx 容器,修改 HTML 文件内容,添加 “coffeelize 欢迎您”
1、进入容器(容器是运行的)
命令解读:
docker exec :进入容器内部,执行一个命令
-it : 给当前进入的容器创建一个标准输入、输出终端,允许我们与容器交互
mn :要进入的容器的名称
bash:进入容器后执行的命令,bash 是一个 linux 终端交互命令
注意:exec 命令可以进入容器修改文件,但是在容器内修改文件是不推荐的,修改了是没有记录(日志的),之后都不知道进行了哪些修改操作
2、进入 nginx 的 HTML 所在目录 /usr/share/nginx/html
容器内部会模拟一个独立的 Linux 文件系统,看起来如同一个 linux 服务器一样
1 2 3 root@b8ae9bcbdde9:/# ls bin dev docker-entrypoint.sh home lib64 mnt proc run srv tmp var boot docker-entrypoint.d etc lib media opt root sbin sys usr
我们进入 Nginx 的目录(至于如何找到这个目录的可能需要在 DockerHub 查看 Nginx 的文档了),可以发现目录下包含 index.html
1 cd /usr/share/nginx/html
3、修改 index.html 的内容
容器内没有 vi 命令,无法直接修改,我们用下面的命令来修改
1 sed -i -e 's#Welcome to nginx#coffeelize欢迎您#g' -e 's#<head>#<head><meta charset="utf-8">#g' index.html
4、验证
访问虚拟机 80 端口,输出页面如下,说明修改成功
5、退出容器
6、停止容器
1 2 3 4 5 6 docker stop mn docker ps docker ps -a
7、启动容器
8、删除容器
数据卷 在之前的 nginx 案例中,修改 nginx 的 html 页面时,需要进入 nginx 内部。并且因为没有编辑器,修改文件也很麻烦,这就是因为容器与数据(容器内文件)耦合带来的后果。要解决这个问题,必须将 数据与容器解耦 ,这就要用到数据卷了
数据卷(volume)是一个虚拟目录,指向宿主机文件系统中的某个目录
一旦完成数据卷挂载,对容器的一切操作都会作用在数据卷对应的宿主机目录了,这样,我们操作宿主机的 /var/lib/docker/volumes/html 目录,就等于操作容器内的 /usr/share/nginx/html 目录了;多个容器可以挂在同一个卷,就可以 “共享” 修改操作了;如果哪一天将容器删除了,没关系,数据卷还在,将新容器在挂载到这个数据卷上就可以了访问之前的数据了
数据卷操作命令 数据卷操作的基本语法如下
create:创建一个 volume
inspect:显示一个或多个 volume 的信息
ls:列出所有的 volume
prune:删除未使用的 volume
rm:删除一个或多个指定的 volume
案例:创建和查看数据卷 需求:创建一个数据卷,并查看数据卷在宿主机的目录位置
1、创建数据卷
1 docker volume create html
2、查看所有数据卷
3、查看数据卷详细信息卷
1 docker volume inspect html
返回信息如下,其中重点关注 Mountpoint 挂载点
1 2 3 4 5 6 7 8 9 10 11 12 [root@localhost ~]# docker volume inspect html [ { "CreatedAt": "2023-01-10T21:32:34+08:00", "Driver": "local", "Labels": {}, "Mountpoint": "/var/lib/docker/volumes/html/_data", "Name": "html", "Options": {}, "Scope": "local" } ]
4、小结
数据卷的作用:将容器与数据分离,解耦合,方便操作容器内数据,保证数据安全
挂载数据卷 我们在创建容器时,可以通过 -v 参数来挂载一个数据卷到某个容器内目录,命令格式如下:
1 2 3 4 5 docker run \ --name mn \ -v html:/root/html \ -p 8080:80 nginx \
这里的 -v 就是挂载数据卷的命令:
docker run
:创建并运行容器
--name mn
:给容器起个名字叫 mn
-v html:/root/html
:把 html 数据卷挂载到容器内的 /root/html 这个目录中
-p 8080:80
:吧宿主机的 8080 端口映射到容器内的 80 端口
nginx:镜像名称
案例:给 nginx 挂载数据卷 需求:创建一个 nginx 容器,修改容器内的 html 目录内的 index.html 内容 分析:上个案例中,我们进入 nginx 容器内部,已经知道 nginx 的 html 目录所在位置 /usr/share/nginx/html ,我们需要把这个目录挂载到 html 这个数据卷上,方便操作其中的内容
0、查看容器是否在运行,并且已经提前创建好了 html 数据卷
1、创建容器并挂载数据卷到容器内的 HTML 目录
1 docker run --name mn -v html:/usr/share/nginx/html -p 80 :80 -d nginx
2、进入 html 数据卷所在位置,并修改 HTML 内容
1 2 3 4 5 6 7 8 docker volume inspect html cd /var/lib/docker/volumes/html/_datals vi index.html
3、在做数据卷挂在时,如果要创建数据卷不存在,docker 会为我们自动创建数据卷
比如在我们使用如下命令前,docker 中是没有 html 数据卷的,一样可以正常使用如下命令,因为 docker 会为我们自动创建 html 数据卷
1 docker run --name mn -v html:/usr/share/nginx/html -p 80 :80 -d nginx
案例:给 MySQL 挂载本地目录 容器不仅仅可以挂载数据卷,也可以直接挂载到宿主机目录上。关联关系如下
带数据卷模式:宿主机目录 –> 数据卷 –> 容器内目录
直接挂载模式:宿主机目录 –> 容器内目录
目录挂载与数据卷挂载的语法是类似的:
-v [宿主机目录]:[容器内目录]
-v [宿主机文件]:[容器内文件]
案例需求:创建并运行一个 MySQL 容器,将宿主机目录直接挂载到容器
1、将课前资料中的 mysql.tar 文件上传到虚拟机的 tmp 目录,通过 load 命令加载为镜像
1 2 3 4 5 6 7 8 cd / cd tmp/ docker load -i mysql.tar docker images
2、创建目录 /tmp/mysql/data
1 2 mkdir -p /tmp/mysql/data
3、创建目录 /tmp/mysql/conf,将课前资料提供的 hmy.cnf 文件上传到 /tmp/mysql/conf
1 2 3 4 mkdir -p /tmp/mysql/conf
hmy.cnf 的文件内容为
1 2 3 4 5 [mysqld] skip-name-resolve character_set_server=utf8 datadir=/var/lib/mysql server-id=1000
4、去 DockerHub 查阅资料 mysql | Docker Hub ,创建并运行 MySQL 容器,要求:
1)挂载 /tmp/mysql/data 到 mysql 容器内数据存储目录 2)挂载 /tmp/mysql/conf/hmy.cnf 到 mysql 容器的配置文件 3)设置 MySQL 密码
官网上给定的运行示例如下
1 docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag
其中 -e 表示运行环境,后面可以直接设置 mysql 密码;-d 表示后台运行;tag 为版本号,其中还缺少了端口号的设置,我们对这个命令进行修改
1 2 3 4 5 6 7 8 docker run \ --name mysql \ -e MYSQL_ROOT_PASSWORD=123 \ -p 3306:3306 \ -v /tmp/mysql/conf/hmy.cnf:/etc/mysql/conf.d/hmy.cnf \ -v /tmp/mysql/data:/var/lib/mysql \ -d \ mysql:5.7.25
但是此时有个报错 (bind: address already in use),因为之前我们已经在虚拟机中运行 MySQL 了,也就是已经占用了宿主机的 3306 端口,这里我们改成 3305 试一下
1 2 3 4 5 6 7 8 9 10 11 12 //删除刚才创建的mysql容器 docker rm mysql //再次执行如下命令,注意端口改为了3305 docker run \ --name mysql \ -e MYSQL_ROOT_PASSWORD=123 \ -p 3305:3306 \ -v /tmp/mysql/conf/hmy.cnf:/etc/mysql/conf.d/hmy.cnf \ -v /tmp/mysql/data:/var/lib/mysql \ -d \ mysql:5.7.25
注意:此处的 /etc/mysql/conf.d 目录,可以合并添加我们创建的 hmy.cnf 配置,而不是将 MySQL 默认的配置文件完全覆盖掉(因为我们创建的配置文件只包含了默认配置的少数配置信息,替换掉默认配置的话配置就不全了)
5、测试 MySQL 连接
通过 Navicat 测试可正常连接
6、小节
数据卷挂载与目录直接挂载的比较:
数据卷挂载耦合度低,由 docker 来管理目录,但是目录较深,不好找
目录挂载耦合度高,需要我们自己管理目录,不过目录容易寻找查看
Dockerfile 自定义镜像 镜像结构 常见的镜像在 DockerHub 就能找到,但是我们自己写的项目就必须自己构建镜像了,而要自定义镜像,就必须先了解镜像的结构才行
镜像是将应用程序及其需要的系统函数库、环境、配置、依赖打包而成。我们以 MySQL 为例,来看看镜像的组成结构
基础镜像(BaseImage):应用依赖的系统函数库、环境、配置、文件等
入口(Entrypoint):镜像运行入口,一般是程序启动的脚本和参数
层(Layer):在 BaseImage 基础上添加安装包、依赖、配置等,每次操作都形成新的层
Dockerfile Dockerfile 是一个文本文件,其中包含一个个的 ** 指令 (Instruction)**,用指令来说明要执行什么操作来构建镜像。每一个指令都会形成一层 Layer。更新详细语法说明,可参考官网文档: https://docs.docker.com/engine/reference/builder
构建 Java 项目 基于 Ubuntu 构建 Java 项目 需求:基于 Ubuntu 镜像构建一个新镜像,运行一个 java 项目
1、新建一个空文件夹 docker-demo
1 2 cd /tmp/ mkdir docker-demo
2、拷贝课前资料中的 docker-demo.jar 文件到 docker-demo 这个目录 3、拷贝课前资料中的 jdk8.tar.gz 文件到 docker-demo 这个目录 4、拷贝课前资料提供的 Dockerfile 到 docker-demo 这个目录
Dockerfile 中的内容如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 FROM ubuntu:16.04 ENV JAVA_DIR=/usr/localCOPY ./jdk8.tar.gz $JAVA_DIR / COPY ./docker-demo.jar /tmp/app.jar RUN cd $JAVA_DIR \ && tar -xf ./jdk8.tar.gz \ && mv ./jdk1.8.0_144 ./java8 ENV JAVA_HOME=$JAVA_DIR/java8ENV PATH=$PATH:$JAVA_HOME/binEXPOSE 8090 ENTRYPOINT java -jar /tmp/app.jar
5、进入 docker-demo
6、运行命令
1 docker build -t javaweb:1.0 .
-t 表示 tag;javaweb 为镜像名称;注意命令后面还有个 .
,表示 dockerfile 所在的目录(构建时告知 dockerfile 在哪)
可以看到 dockerfile 共有 9 个指令,也就分为了 9 个 step,每个指令执行都会创建出一个层
7、通过命令查看构建好的镜像
1 2 3 4 5 6 7 [root@localhost docker-demo]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE javaweb 1.0 c94aff541e94 42 seconds ago 722MB nginx latest 605c77e624dd 12 months ago 141MB redis latest 7614ae9453d1 12 months ago 113MB ubuntu 16.04 b6f507652425 16 months ago 135MB mysql 5.7.25 98455b9624a9 3 years ago 372MB
可以看到我们基于 ubuntu 构建的(配置好 java 环境的)javaweb 项目的镜像已经构建好了
可以通过命令来运行镜像(8090 端口在 dockerfile 中已经声明暴露了端口)
1 docker run --name web -p 8090 :8090 -d javaweb:1.0
浏览器访问如下地址,可以发现我们的项目(之前我们的 docker-demo.jar 项目)正常跑起来了
虚拟机中运行 docker –> docker 中运行 ubuntu –> ubuntu 中运行 docker-demo java 项目😂,虚拟机内存开始吃紧了
小结 分析:其实我们的 java 项目真正只用到了如下一行
1 COPY ./docker-demo.jar /tmp/app.jar
dockerfile 文件内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 FROM ubuntu:16.04 ENV JAVA_DIR=/usr/localCOPY ./jdk8.tar.gz $JAVA_DIR / COPY ./docker-demo.jar /tmp/app.jar RUN cd $JAVA_DIR \ && tar -xf ./jdk8.tar.gz \ && mv ./jdk1.8.0_144 ./java8 ENV JAVA_HOME=$JAVA_DIR/java8ENV PATH=$PATH:$JAVA_HOME/binEXPOSE 8090 ENTRYPOINT java -jar /tmp/app.jar
那么我们之后在构建 Java 项目镜像时,可以先构建如下不会改变的层做一个镜像,然后在基于这个镜像来构建。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 FROM ubuntu:16.04 ENV JAVA_DIR=/usr/localCOPY ./jdk8.tar.gz $JAVA_DIR / RUN cd $JAVA_DIR \ && tar -xf ./jdk8.tar.gz \ && mv ./jdk1.8.0_144 ./java8 ENV JAVA_HOME=$JAVA_DIR/java8ENV PATH=$PATH:$JAVA_HOME/bin
而实际上,有人也已经构建好了这个镜像了,我们直接拿来用就行,镜像名为 java:8-alpine
1 2 3 4 5 6 7 8 FROM java:8 -alpineCOPY ./app.jar /tmp/app.jar EXPOSE 8090 ENTRYPOINT java -jar /tmp/app.jar
DockerCompose Docker Compose 可以基于 Compose 文件帮我们快速部署分布式应用,而无需手动一个个创建和运行容器
初识 DockerCompose Compose 文件是一个文本文件,通过指令定义集群中的每个容器如何运行。格式如下(相当于把 docker run 中的所有指令转换为了 Compose 指令了):
1 2 3 4 5 6 7 8 9 10 11 12 13 version: "3.8" services: mysql: image: mysql:5.7 .25 environment: MYSQL_ROOT_PASSWORD: 123 volumes: - "/tmp/mysql/data:/var/lib/mysql" - "/tmp/mysql/conf/hmy.cnf:/etc/mysql/conf.d/hmy.cnf" web: build: . ports: - "8090:8090"
上面的 Compose 文件就描述一个项目,其中包含两个容器
mysql:一个基于 mysql:5.7.25
镜像构建的容器,并且挂载了两个目录
为什么没有定义端口呢:因为 MySQL 运行在微服务当中,供内部使用无需对外开放
无需定义后台运行,默认就是后台运行
web:一个基于 docker build
临时构建的镜像容器,映射端口时 8090
为什么没有指定镜像:因为通过 build 就可以构建镜像
安装 DockerCompose 1、下载
或者通过本地文件准备好的文件直接上传,上传至 /usr/local/bin/
目录
2、修改文件权限
1 2 # 修改权限 chmod +x /usr/local/bin/docker-compose
3、Base 自动补全命令
之后使用 Docker Compose 时就会有补全提示
此时可能会报:拒绝连接的错误,需要执行如下命令修改 hosts 文件
1 echo "199.232.68.133 raw.githubusercontent.com" >> /etc/hosts
案例:利用 DockerCompose 部署 需求:将之前学习的 cloud-demo 微服务集群利用 DockerCompose 部署
1、查看课前资料提供的 cloud-demo 文件夹,里面已经编写好了 docker-compose 文件
课前资料提供的 cloud-demo 文件夹,里面已经编写好了 docker-compose 文件,而且每个微服务都准备了一个独立的目录。对于每一个微服务目录,其中都包含一个 Dockerfile 文件和对于的微服务 jar 包。最外层包含 docker-compose.yml 配置文件,文件内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 version: "3.2" services: nacos: image: nacos/nacos-server environment: MODE: standalone ports: - "8848:8848" mysql: image: mysql:5.7 .25 environment: MYSQL_ROOT_PASSWORD: 123 volumes: - "$PWD/mysql/data:/var/lib/mysql" - "$PWD/mysql/conf:/etc/mysql/conf.d/" userservice: build: ./user-service orderservice: build: ./order-service gateway: build: ./gateway ports: - "10010:10010"
这几个微服务(mysql、userservice、orderservice 以及 gateway)中,只有网关暴露了端口,因为网关是外部访问微服务的入口。其他微服务都需要注册到 Nacos 服务中
MySQL 微服务中需要的表和数据课程资料也已经为我们准备好了
2、修改自己的 cloud-demo 项目,将数据库、nacos 地址都命名为 docker-compose 中的服务名
因为微服务将来要部署为 docker 容器,而容器之间互联不是通过 IP 地址,而是通过容器名。这里我们将 order-service、user-service、gateway 服务的 mysql、nacos 地址都修改为基于容器名的访问
比如 user-service 中的 bootstrap 配置文件
1 2 3 4 5 6 7 8 9 10 11 spring: application: name: userservice # 服务名称 profiles: active: dev #开发环境,这里是dev cloud: nacos: - server-addr: localhost:8848 # Nacos地址 + server-addr: nacos:8848 # Nacos地址 config: file-extension: yaml # 文件后缀名
application.yml 配置文件中
1 2 - url: jdbc:mysql://localhost:3306/cloud_user?useSSL=false + url: jdbc:mysql://mysql:3306/cloud_user?useSSL=false
同理,order-service 和 gateway 微服务的配置文件也这样修改
3、使用 maven 打包工具,将项目中的每个微服务都打包为 app.jar
为什么都打包成 app.jar 呢 –> 因为我们在微服务目录下的 Dockerfile 文件里是这样配置的,我们配置的名称都是 app.jar
1 2 3 FROM java:8 -alpine COPY ./app.jar /tmp/app.jar ENTRYPOINT java -jar /tmp/app.jar
那么,既然各个微服务打包完成都需要叫这个 app.jar 名字,我们是否可以修改配置文件实现项目打包自动叫这个名字呢 –> 可以的,在各个微服务的 pom 文件中添加如下配置
1 2 3 4 5 6 7 8 9 <build > <finalName > app</finalName > <plugins > <plugin > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-maven-plugin</artifactId > </plugin > </plugins > </build >
通过 Maven 的 Package 来打包
4、将打包好的 app.jar 拷贝到 cloud-demo 中的每一个对应的微服务子目录中
5、将 cloud-demo 上传至虚拟机 (tmp 目录),利用 docker-compose up -d 来部署
1 2 3 4 5 6 7 cd / cd /tmp/ cd cloud-demo/ docker-compose up -d
up:表示创建并执行容器
down:停止并删除容器
其他命令可以通过 help 命令查看
6、查看打包好的镜像和运行的容器
1 2 3 4 5 6 7 8 9 10 11 12 [root@localhost cloud-demo]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE cloud-demo_gateway latest 3ce691e26939 About a minute ago 185MB cloud-demo_orderservice latest b81195944331 About a minute ago 187MB cloud-demo_userservice latest 2dc6d8c88bdc About a minute ago 184MB javaweb 1.0 c94aff541e94 3 hours ago 722MB nginx latest 605c77e624dd 12 months ago 141MB redis latest 7614ae9453d1 12 months ago 113MB ubuntu 16.04 b6f507652425 16 months ago 135MB nacos/nacos-server latest bdf60dc2ada3 17 months ago 1.05GB mysql 5.7.25 98455b9624a9 3 years ago 372MB java 8-alpine 3fd9dd82815c 5 years ago 145MB
虚拟机 2G 内存快要炸了😳,开始借用交换内存了
7、通过查看日志可发现 order-service 有报错
1 2 3 4 5 6 7 docker-compose logs -f Ctrl+C docker-compose restart gateway userservice orderservice
原因是因为 Nacos 微服务启动晚于 order-service,导致报错。关键是报错之后没有进行重新启动 –> 因此,我们最好是先启动 Nacos 微服务,之后再启动 order-service 等系列微服务
浏览器访问如下,均可正常接收到数据
至此,DockerCompose 部署微服务完成
8、删除掉这些容器吧,虚拟机要炸了
1 2 docker-compose down --rmi all
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 [root@localhost cloud-demo]# docker-compose down --rmi all Stopping cloud-demo_nacos_1 ... done Stopping cloud-demo_userservice_1 ... done Stopping cloud-demo_gateway_1 ... done Stopping cloud-demo_mysql_1 ... done Stopping cloud-demo_orderservice_1 ... done Removing cloud-demo_nacos_1 ... done Removing cloud-demo_userservice_1 ... done Removing cloud-demo_gateway_1 ... done Removing cloud-demo_mysql_1 ... done Removing cloud-demo_orderservice_1 ... done Removing network cloud-demo_default Removing image nacos/nacos-server Removing image mysql:5.7.25 Removing image cloud-demo_userservice Removing image cloud-demo_orderservice Removing image cloud-demo_gateway
Docker 镜像仓库 简化版镜像仓库 Docker 官方的 Docker Registry 是一个基础版本的 Docker 镜像仓库,具备仓库管理的完整功能,但是没有图形化界面
1 2 3 4 5 6 docker run -d \ --restart=always \ --name registry \ -p 5000:5000 \ -v registry-data:/var/lib/registry \ registry
命令中挂载了一个数据卷 registry-data 到容器内的 /var/lib/registry 目录,这是私有镜像库存放数据的目录,访问如下链接可以查看当前私有镜像服务中包含的镜像
1 http://yourip:5000/v2/_catalog
带有图形化界面版本 操作此步骤前,需要先完成 Docker 信任地址配置
使用 DockerCompose 部署带有图象界面的 DockerRegistry,命令如下
1 2 3 4 5 6 7 8 9 cd /cd /tmp/mkdir registry-ui cd registry-uitouch docker-compose.yml //修改这个yml文件,内容如下代码块 //修改yml文件完成后执行docker-compose docker-compose up -d
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 version: '3.0' services: registry: image: registry volumes: - ./registry-data:/var/lib/registry ui: image: joxit/docker-registry-ui:static ports: - 8080 :80 environment: - REGISTRY_TITLE=coffeelize私有仓库 - REGISTRY_URL=http://registry:5000 depends_on: - registry
通过访问如下地址,即可访问我们创建的带有图形界面的 Docker 镜像仓库了
配置 Docker 信任地址 我们的私服采用的是 http 协议,默认不被 Docker 信任,所以需要做一个配置
1 2 3 4 5 6 7 8 vi /etc/docker/daemon.json "insecure-registries" :["http://192.168.119.128:8080" ]systemctl daemon-reload systemctl restart docker
在添加内容时,注意多个配置之间别把逗号忘加了
1 2 3 4 { "registry-mirrors": ["https://5vycoa8o.mirror.aliyuncs.com"], + "insecure-registries":["http://192.168.119.128:8080"] }
在私有镜像仓库中推送或拉去镜像 推送镜像到私有镜像服务必须先 tag,步骤如下:
1、重新 tag 本地镜像(重命名镜像,并且以镜像仓库地址为前缀),名称前缀为私有仓库的地址:192.168.119.128:8080/
1 docker tag nginx:latest 192.168.119.128:8080/nginx:1.0
利用 tag 命令,可以将一个镜像重命名,这里我们对之前下载的最新版 Nginx 镜像进行操作
此时,查看本地的镜像,就可以找到我们打包并且重命名后的镜像了,可以发现这两个镜像的 ID(605c77e624dd)其实是一样的
1 2 192.168.119.128:8080/nginx 1.0 605c77e624dd 12 months ago 141MB nginx latest 605c77e624dd 12 months ago 141MB
2、推送镜像
1 docker push 192.168.119.128:8080/nginx:1.0
3、拉取镜像
1 docker pull 192.168.150.101:8080/nginx:1.0