👑4 项目实战
💫4.1 Docker Desktop on Windows
想要在开发环境能够结合 maven 自动化构建镜像,就需要先给你自己的电脑安装一个 Docker,目前 Docker 针对 Windows 和 Mac 平台都推出了 Desktop 桌面版本,直接按照官方文档安装即可。
官方文档:https://docs.docker.com/desktop/install/windows-install/
4.1.1 开启虚拟化服务
Hyper-V
如果服务中没有 Hyper-V,创建一个文本文件,保存下方内容
pushd "%~dp0"
dir /b %SystemRoot%\servicing\Packages\*Hyper-V*.mum >hyper-v.txt
for /f %%i in ('findstr /i . hyper-v.txt 2^>nul') do dism /online /norestart /add-package:"%SystemRoot%\servicing\Packages\%%i"
del hyper-v.txt
Dism /online /enable-feature /featurename:Microsoft-Hyper-V-All /LimitAccess /ALL
保存后,将文本文件后缀修改为 cmd
,并且用管理员身份运行,运行完成后输入 y
重启电脑,之后再打开 Hyper-V
就可以运行了。
适用于Linux的Windows子系统 & 虚拟机平台
4.1.2 wsl 安装 ubuntu
安装
# 设置 wsl2 为默认版本
wsl --set-default-version 2
# 安装 ubuntu
wsl --install -d Ubuntu
# 安装完成后,重新打开的窗口需要输入新的 linux 用户名与密码
# 用户名密码填完后,使用 PowerShell 查看当前版本,确认版本是否为 2,如果为 2 则不用升级
wsl -l -v
升级 wsl2
- 主要原因:wsl2 版本中拥有完整的 Linux 内核功能,而wsl1 版本中是不完整的 Linux 内核功能。
如果以前已经装过其他 linux 子系统,且 wsl 版本为 1 的,按照以下步骤升级
找到 软件 目录中的 wsl_update_x64.msi 执行并安装
设置 wsl2 为默认版本 wsl --set-default-version 2
查询需要升级的版本 wsl -l -v
选择对应的版本升级 wsl --set-version <第三步查到的名称> 2
输出转换完成后表示成功,通过 wsl -l -v 再次确认版本是否转换成功
4.1.3 安装 Docker Desktop
找到软件中的安装包,直接双击安装即可,所有选项都默认,安装完成后需要重启电脑,电脑重启完毕后再次打开 Docker Desktop,需要接受订阅服务协议才可使用
闪退问题
基于第一步开启对应的三个功能
一直卡在Docker engine starting
如果出现一直卡在 Engine starting,按住 shift 键在任意空白位置右键,打开 Power Shell,并执行如下两行命令
cd "C:\Program Files\Docker\Docker"
./DockerCli.exe -SwitchDaemon
4.1.4 客户端设置
启用 wsl 虚拟机子系统
在设置界面中找到 Resources > WSL Integration 选项
勾选 Enable integration with my default WSL distro
且启用下方你所安装的 linux 子系统,如 Ubuntu
修改完成后,点击右下方的 Apply & restart 按钮重启 Docker
配置仓库与镜像
找到设置页面中的 Docker Engine,进去以后修改原先的 json 文件,加入如下内容
insecure-registries:信任的仓库列表,用于 pull/push 镜像
registry-mirrors: 镜像仓库列表,用于提升镜像下载速度
"insecure-registries": [
"10.0.0.51:5000",
"10.0.0.51:5001"
],
"registry-mirrors": [
"https://po13h3y1.mirror.aliyuncs.com",
"https://registry.docker-cn.com",
"https://hub-mirror.c.163.com",
"https://docker.mirrors.ustc.edu.cn"
]
修改完毕后点击右下方的 Apply & restart 按钮
💫4.2 IntelliJ IDEA 构建 Docker 镜像
目的:将开发人员的项目构建成为Docker 镜像,然后将Docker 镜像运行成 Docker 容器。
4.2.1 maven 插件
必须要进行 maven 的加速配置可以参考文档:
Maven 加速参考文档:Maven 阿里云镜像加速
4.2.1.1 常见插件
- Spring Boot Maven 打包插件内置的 build-image
官方文档:https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/htmlsingle/#build-image
Spring Boot 2.3 版本后默认集成了用于构建 Maven 镜像的插件,只要是 Spring Boot 项目,就可以直接使用,前提是本地环境中安装了 Docker。
命令:
mvn spring-boot:build-image
# 并不是传统的Dockerfile形式,管理员不需要手动编写Dockerfile
# 该插件会提供相应的配置信息,可以基于提供的配置信息,把需要定制的内容编写在配置文件中
# 使用简单,就意味着封装的程度就更高,层级高,意味着灵活性较低,定制化的功能就较低了
拓展配置:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<!-- 指定打包后的镜像名 -->
<imageName>${groupId}/${project.artifactId}:${project.version}</imageName>
<docker>
<!-- 配置发布的仓库信息 -->
<publishRegistry>
<url>http://10.0.0.51:5000</url>
<username>admin</username>
<password>wolfcode</password>
</publishRegistry>
</docker>
</configuration>
</plugin>
- Google 的 jib-maven-plugin
Jib 是一个 Maven
和 Gradle
插件,用来创建 Docker 镜像。它最大的特点是,你的本地可以没有 Docker 也可以进行构建,同样也不需要编写 Dockerfile 文件,不用改动代码,甚至不用修改 pom.xml
文件,运行如下命令即可:
# 国外使用频率较高,因为使用的Google的地址
# 使用简单,就意味着封装的程度就更高,层级高,意味着灵活性较低,定制化的功能就较低了
mvn compile com.google.cloud.tools:jib-maven-plugin:2.3.0:dockerBuild
- Spotify 的 dockerfile-maven-plugin
专门基于 Dockerfile 构建镜像的插件,也是目前市面上用的比较多的镜像构建方式之一。[ 国内使用插件较多,是使用开发人员编写的Dockerfile文件进行构建 ]
<plugin>
<groupId>com.spotify</groupId>
<artifactId>dockerfile-maven-plugin</artifactId>
<version>1.4.13</version>
<executions>
<execution>
<id>default</id>
<!-- 自定义构建、推送命令 -->
<goals>
<goal>build</goal>
<goal>push</goal>
</goals>
</execution>
</executions>
<configuration>
<!-- 打包后的完整镜像名:仓库路径/组织/镜像名 -->
<repository>10.0.0.51:5000/wolfcode/${project.artifactId}</repository>
<!-- 镜像版本号 -->
<tag>${project.version}</tag>
<!-- 读取 settings.xml 文件中的认证信息 -->
<useMavenSettingsForAuth>true</useMavenSettingsForAuth>
<buildArgs>
<!-- jar 所在目录 -->
<JAR_FILE>target/${project.artifactId}-${project.version}.jar</JAR_FILE>
</buildArgs>
</configuration>
</plugin>
- 查看 Maven 的
settings.xml
配置文件中的连接镜像仓库的配置
4.2.1.2 Dockerfile 配置
## 基础镜像
## AdoptOpenJDK 停止发布 OpenJDK 二进制,而 Eclipse Temurin 是它的延伸,提供更好的稳定性
FROM eclipse-temurin:8-jre
## 作者
MAINTAINER xiaoliu <liugang@wolfcode.cn>
## 定义参数
ARG JAR_FILE
## 创建并进入工作目录
RUN mkdir -p /wolfcode
WORKDIR /wolfcode
## maven 插件构建时得到 buildArgs 种的值
COPY ${JAR_FILE} app.jar
## 设置 TZ 时区
## 设置 JAVA_OPTS 环境变量,可通过 docker run -e "JAVA_OPTS=" 进行覆盖
ENV TZ=Asia/Shanghai JAVA_OPTS="-Xms256m -Xmx256m"
## 暴露端口
EXPOSE 8080
## 容器启动命令
## CMD 第一个参数之后的命令可以在运行时被替换
CMD java ${JAVA_OPTS} -Djava.security.egd=file:/dev/./urandom -jar app.jar
在 Dockerfile 中 CMD
比 ENTRYPOINT
的扩展性要高得多,因为 CMD
可以被 docker run
后面的参数进行替换。可以实现相应的功能。
查看本地开发环境的 Docker Image 镜像
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
eclipse-temurin 8-jre 50d0169500d4 9 days ago 221MB
tomcat 9.0 b8e65a4d736d 16 months ago 680MB
4.2.1.3 构建镜像
# mvn dockerfile:build
# 查看构建镜像信息
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
10.0.0.51:5000/wolfcode/springboot-docker-demo 1.0.0 5f1e4cf8edca 54 seconds ago 241MB
eclipse-temurin 8-jre 50d0169500d4 9 days ago 221MB
tomcat 9.0 b8e65a4d736d 16 months ago 680MB
$ docker history 10.0.0.51:5000/wolfcode/springboot-docker-demo:1.0.0
IMAGE CREATED CREATED BY SIZE COMMENT
5f1e4cf8edca About a minute ago /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "java… 0B
dcfd3534a64c About a minute ago /bin/sh -c #(nop) EXPOSE 8080 0B
7c36a50ffaf7 About a minute ago /bin/sh -c #(nop) ENV TZ=Asia/Shanghai JAVA… 0B
979358c07b4d About a minute ago /bin/sh -c #(nop) COPY file:fc0cd155a74929a2… 19.7MB
b4023efffb6d About a minute ago /bin/sh -c #(nop) WORKDIR /wolfcode 0B
db9c2416c218 About a minute ago |1 JAR_FILE=target/springboot-docker-demo-1.… 0B
ad4967b4b961 About a minute ago /bin/sh -c #(nop) ARG JAR_FILE 0B
8f808c67b682 About a minute ago /bin/sh -c #(nop) MAINTAINER xiaoliu <liuga… 0B
50d0169500d4 9 days ago /bin/sh -c echo Verifying install ... &&… 0B
<missing> 9 days ago /bin/sh -c set -eux; ARCH="$(dpkg --prin… 109MB
<missing> 9 days ago /bin/sh -c #(nop) ENV JAVA_VERSION=jdk8u372… 0B
<missing> 9 days ago /bin/sh -c apt-get update && DEBIAN_FRON… 34.7MB
<missing> 9 days ago /bin/sh -c #(nop) ENV LANG=en_US.UTF-8 LANG… 0B
<missing> 9 days ago /bin/sh -c #(nop) ENV PATH=/opt/java/openjd… 0B
<missing> 9 days ago /bin/sh -c #(nop) ENV JAVA_HOME=/opt/java/o… 0B
<missing> 2 weeks ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> 2 weeks ago /bin/sh -c #(nop) ADD file:2fc6364d149eccc7f… 77.8MB
<missing> 2 weeks ago /bin/sh -c #(nop) LABEL org.opencontainers.… 0B
<missing> 2 weeks ago /bin/sh -c #(nop) LABEL org.opencontainers.… 0B
<missing> 2 weeks ago /bin/sh -c #(nop) ARG LAUNCHPAD_BUILD_ARCH 0B
<missing> 2 weeks ago /bin/sh -c #(nop) ARG RELEASE 0B
4.2.1.4 推送镜像到仓库
在 maven
的 settings.xml
文件的 servers
标签中,增加服务认证配置信息
<server>
<id>10.0.0.51:5000</id>
<username>admin</username>
<password>Admin@h3c</password>
</server>
# mvn dockerfile:push
- IDEA 中的 maven 插件中拥有 “
dockerfile
” 插件并且其中有"dockerfile:push
" 的操作,执行之后就会推送到远程仓库中(使用的是 Nexus 镜像仓库)
- 登录到 Nexus 镜像仓库,查看到推送镜像的情况
- 自动化的将镜像运行成容器[ 需要研究脚本的指令的作用 ]
- 将
docker-deploy.sh
脚本文件上传到服务器中
$ mkdir -p /opt/springboot-docker-demo
$ vim docker-deploy.sh
# 参考示例:脚本内容
示例:脚本内容
#!/bin/bash
## 第一个参数:up|start|stop|restart|rm
COMMAND=$1
## app 名称
APP_NAME=$2
## 如果没有给 app 名称,默认就叫 app
if [ -z $APP_NAME ]; then
APP_NAME="springboot-docker-demo"
fi
## 暴露的端口
EXPOSE_PORT=8888
## 项目/组织
NAMESPACE=wolfcode
## 版本号
TAG=1.0.0
## 仓库地址
REGISTRY_SERVER=10.0.0.51:5000
## 用户名
USERNAME=admin
## 密码
PASSWORD=Admin@h3c
## 镜像名称
IMAGE_NAME="$REGISTRY_SERVER/$NAMESPACE/$APP_NAME:$TAG"
## 使用说明,用来提示输入参数
function usage() {
echo "Usage: sh docker-deploy.sh [up|start|stop|restart|rm]"
exit 1
}
## 登录仓库
function login() {
echo "docker login -u $USERNAME --password-stdin $REGISTRY_SERVER"
echo "$PASSWORD" | docker login -u $USERNAME --password-stdin $REGISTRY_SERVER
}
## 启动容器
function start() {
# 检查容器是否存在
CONTAINER_NAME=$(docker ps | grep "$APP_NAME" | awk '{print $NF}')
# 存在就不启动了
if [ -n "$CONTAINER_NAME" ]; then
echo "container $CONTAINER_NAME aready started..."
exit 1
fi
# 镜像如果不存在需要先登录
IMAGE=$(docker images | grep "$APP_NAME" | awk '{print $3}')
if [ -z "$IMAGE" ]; then
login
fi
# 容器不存在就启动
echo "starting container $APP_NAME..."
docker run -d --restart=always --name $APP_NAME -p $EXPOSE_PORT:8080 $IMAGE_NAME
echo "container $APP_NAME started..."
}
## 停止容器
function stop() {
# 检查容器是否存在
CONTAINER_NAME=$(docker ps | grep "$APP_NAME" | awk '{print $NF}')
# 不存在就不需要停止
if [ -z "$CONTAINER_NAME" ]; then
echo "container $CONTAINER_NAME not running..."
exit 1
fi
# 存在就停止容器
echo "stoping container $APP_NAME..."
docker stop $CONTAINER_NAME
echo "container $APP_NAME stopted..."
}
## 重启容器
function restart() {
# 先停止
stop
# 再启动
start
}
## 删除容器、镜像
function rm() {
# 获取容器名称
CONTAINER_NAME=$(docker ps | grep "$APP_NAME" | awk '{print $NF}')
if [ -n "$CONTAINER_NAME" ]; then
# 停止容器
stop
# 删除容器
echo "removing container $APP_NAME..."
docker rm $CONTAINER_NAME
echo "container $APP_NAME removed..."
fi
# 获取镜像 id
IMAGE=$(docker images | grep "$APP_NAME" | awk '{print $3}')
if [ -n "$IMAGE" ]; then
# 删除镜像
echo "removing image $IMAGE..."
docker rmi $IMAGE
echo "image $IMAGE removed..."
fi
}
# 重新拉取镜像并启动容器
function up() {
# 删除旧的镜像与容器
rm
# 拉取新的镜像并启动容器
start
}
# 根据输入参数,选择执行对应方法,不输入则执行使用说明
case "$COMMAND" in
"up")
up
;;
"start")
start
;;
"stop")
stop
;;
"restart")
restart
;;
"rm")
rm
;;
*)
usage
;;
esac
- 执行脚本
$ chmod +x docker-deploy.sh
$ sh docker-deploy.sh up
# 查看镜像的情况
$ docker images 10.0.0.51:5000/wolfcode/springboot-docker-demo
REPOSITORY TAG IMAGE ID CREATED SIZE
10.0.0.51:5000/wolfcode/springboot-docker-demo 1.0.0 5f1e4cf8edca 43 minutes ago 241MB
# 查看运行容器的情况
$ docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
75a3ed93a06c 10.0.0.51:5000/wolfcode/springboot-docker-demo:1.0.0 "/bin/sh -c 'java ${…" 30 seconds ago Up 26 seconds 0.0.0.0:8888->8080/tcp, :::8888->8080/tcp springboot-docker-demo
- 访问页面
$ curl 10.0.0.51:8888
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Spring Boot Docker Demo</title>
</head>
<body>
<h1>Spring Boot in Docker...</h1>
</body>
</html>
$ curl 10.0.0.51:8888/hello
Spring Boot in Docker...
- IDEA 新增接口代码,并重新进行
package
打包构建镜像,然后进行镜像的推送到 Nexus 镜像仓库中[ 执行 maven 插件中拥有 “dockerfile
” 插件并且其中有"dockerfile:push
" 的操作 ]
# 在服务器中执行脚本docker-deploy.sh
$ bash docker-deploy.sh up
$ curl 10.0.0.51:8888/new
New Interface...
4.2.2 Alibaba Cloud Toolkit
Alibaba Cloud Toolkit(后文简称Cloud Toolkit)可以帮助开发者更高效地部署、测试、开发和诊断应用。Cloud Toolkit与主流IDE及阿里云其他产品无缝集成,帮助您大大简化应用部署到服务器,尤其是阿里云服务器中的操作。您还可以通过其内嵌的Arthas程序诊断、Terminal Shell终端和MySQL执行器等工具,简化应用开发、测试和诊断的过程。
产品功能
-
部署应用
-
- 部署应用到ECS:完成编码后,利用Cloud Toolkit快速将应用部署至ECS指定目录。
- 部署应用到EDAS:将本地代码和云端应用进行关联后,可以实现自动化的部署。
- 部署应用到Kubernetes:将本地代码和云端容器进行关联后,可以实现自动化的镜像上传和部署。
- 部署应用到远程服务器:支持SSH标准协议,可以将应用部署到任意机器。
-
内置终端Terminal:在本地IDE内,开发者可以直接通过内置的终端Terminal,快速登录所有支持标准SSH协议的机器。
-
文件上传:在本地IDE内,开发者可以一键将本地文件或者远程URL上传到服务器指定目录。
-
SLS日志查看:在本地IDE内,开发者可以查看/分析阿里云的SLS日志。
-
内置数据库SQL Console:在本地IDE内,开发者可以浏览阿里云的RDS资源。若已配置用户名和密码,可通过内置的SQL Console连接上RDS实例,并快速执行SQL语句。
-
Arthas诊断:在本地IDE中即可使用Arthas来实现远程诊断。
-
创建Dubbo应用:在本地IDE中快速创建Dubbo应用。
-
SSH代理功能:可使用Cloud Toolkit支持SSH代理的功能,通过添加代理机、添加部署机器和设置代理等操作,快速打通网络环境。
4.2.2.1 安装CouTookit
打开 IDEA 设置,进入 plugins
菜单,在插件市场中搜索 Alibaba Cloud Toolkit
,找到后下载并重启 IDEA。
- 重启 IDEA 之后进行添加主机
添加主机完成
- 注意编辑 IDEA 中
pom.xml
文件中的对 Nexus 地址的情况
- 并且在
pom.xml
文件中添加内容[ 否则会出现由于 maven-plugin 版本过低导致构建镜像失败 ]
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
</plugin>
<plugins>
<build>
- IDEA 中的 “maven” 选项中的
package
进行对项目打包并进行构建镜像
- 可以查看到本地镜像的情况
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
10.0.0.51:5000/wolfcode/javaweb-docker-demo 1.0-SNAPSHOT 227fdd3bad4e 6 minutes ago 680MB
10.0.0.51:5000/wolfcode/springboot-docker-demo 1.0.0 5f1e4cf8edca 2 hours ago 241MB
eclipse-temurin 8-jre 50d0169500d4 9 days ago 221MB
tomcat 9.0 b8e65a4d736d 16 months ago 680MB
# 查看镜像的历史记录
$ docker history 10.0.0.51:5000/wolfcode/javaweb-docker-demo:1.0-SNAPSHOT
IMAGE CREATED CREATED BY SIZE COMMENT
227fdd3bad4e 8 minutes ago /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "bin/… 0B
950d2ee47fb8 8 minutes ago /bin/sh -c #(nop) WORKDIR /usr/local/tomcat/ 0B
ad356019409c 8 minutes ago /bin/sh -c #(nop) COPY file:a62016ebf68d72cb… 4.08kB
04890adc5c7f 8 minutes ago /bin/sh -c #(nop) ARG JAR_FILE 0B
61fc3683f82e 8 minutes ago /bin/sh -c #(nop) WORKDIR /usr/local/tomcat/… 0B
9715085bc38f 8 minutes ago /bin/sh -c #(nop) MAINTAINER xiaoliu<liugan… 0B
b8e65a4d736d 16 months ago /bin/sh -c #(nop) CMD ["catalina.sh" "run"] 0B
<missing> 16 months ago /bin/sh -c #(nop) EXPOSE 8080 0B
<missing> 16 months ago /bin/sh -c set -eux; nativeLines="$(catalin… 0B
<missing> 16 months ago /bin/sh -c set -eux; savedAptMark="$(apt-m… 20.2MB
<missing> 16 months ago /bin/sh -c #(nop) ENV TOMCAT_SHA512=b4c2c85… 0B
<missing> 16 months ago /bin/sh -c #(nop) ENV TOMCAT_VERSION=9.0.56 0B
<missing> 16 months ago /bin/sh -c #(nop) ENV TOMCAT_MAJOR=9 0B
<missing> 16 months ago /bin/sh -c #(nop) ENV GPG_KEYS=48F8E69F6390… 0B
<missing> 16 months ago /bin/sh -c #(nop) ENV LD_LIBRARY_PATH=/usr/… 0B
<missing> 16 months ago /bin/sh -c #(nop) ENV TOMCAT_NATIVE_LIBDIR=… 0B
<missing> 16 months ago /bin/sh -c #(nop) WORKDIR /usr/local/tomcat 0B
<missing> 16 months ago /bin/sh -c mkdir -p "$CATALINA_HOME" 0B
<missing> 16 months ago /bin/sh -c #(nop) ENV PATH=/usr/local/tomca… 0B
<missing> 16 months ago /bin/sh -c #(nop) ENV CATALINA_HOME=/usr/lo… 0B
<missing> 16 months ago /bin/sh -c #(nop) CMD ["jshell"] 0B
<missing> 16 months ago /bin/sh -c set -eux; arch="$(dpkg --print-… 343MB
<missing> 16 months ago /bin/sh -c #(nop) ENV JAVA_VERSION=11.0.13 0B
<missing> 16 months ago /bin/sh -c #(nop) ENV LANG=C.UTF-8 0B
<missing> 16 months ago /bin/sh -c #(nop) ENV PATH=/usr/local/openj… 0B
<missing> 16 months ago /bin/sh -c { echo '#/bin/sh'; echo 'echo "$J… 27B
<missing> 16 months ago /bin/sh -c #(nop) ENV JAVA_HOME=/usr/local/… 0B
<missing> 16 months ago /bin/sh -c set -eux; apt-get update; apt-g… 11.3MB
<missing> 16 months ago /bin/sh -c apt-get update && apt-get install… 152MB
<missing> 16 months ago /bin/sh -c set -ex; if ! command -v gpg > /… 18.9MB
<missing> 16 months ago /bin/sh -c set -eux; apt-get update; apt-g… 10.7MB
<missing> 16 months ago /bin/sh -c #(nop) CMD ["bash"] 0B
<missing> 16 months ago /bin/sh -c #(nop) ADD file:c03517c5ddbed4053… 124MB
- IDEA 中的 maven 插件中拥有 “
dockerfile
” 插件并且其中有"dockerfile:push
" 的操作,执行之后就会推送到远程仓库中(使用的是 Nexus 镜像仓库)
- 登录到 Nexus 镜像仓库,查看到推送镜像的情况
- 将
docker-deploy.sh
脚本文件上传到服务器中
$ mkdir -p /opt/javaweb-docker-demo
$ vim docker-deploy.sh
# 参考示例:脚本内容
示例:脚本内容
#!/bin/bash
## 第一个参数:up|start|stop|restart|rm
COMMAND=$1
## app 名称
APP_NAME=$2
## 如果没有给 app 名称,默认就叫 app
if [ -z $APP_NAME ]; then
APP_NAME="javaweb-docker-demo"
fi
## 暴露的端口
EXPOSE_PORT=8808
## 项目/组织
NAMESPACE=wolfcode
## 版本号
TAG=1.0-SNAPSHOT
## 仓库地址
REGISTRY_SERVER=10.0.0.51:5000
## 用户名
USERNAME=admin
## 密码
PASSWORD=Admin@h3c
## 镜像名称
IMAGE_NAME="$REGISTRY_SERVER/$NAMESPACE/$APP_NAME:$TAG"
## 使用说明,用来提示输入参数
function usage() {
echo "Usage: sh docker-deploy.sh [up|start|stop|restart|rm]"
exit 1
}
## 登录仓库
function login() {
echo "docker login -u $USERNAME --password-stdin $REGISTRY_SERVER"
echo "$PASSWORD" | docker login -u $USERNAME --password-stdin $REGISTRY_SERVER
}
## 启动容器
function start() {
# 检查容器是否存在
CONTAINER_NAME=$(docker ps | grep "$APP_NAME" | awk '{print $NF}')
# 存在就不启动了
if [ -n "$CONTAINER_NAME" ]; then
echo "container $CONTAINER_NAME aready started..."
exit 1
fi
# 镜像如果不存在需要先登录
IMAGE=$(docker images | grep "$APP_NAME" | awk '{print $3}')
if [ -z "$IMAGE" ]; then
login
fi
# 容器不存在就启动
echo "starting container $APP_NAME..."
docker run -d --restart=always --name $APP_NAME -p $EXPOSE_PORT:8080 $IMAGE_NAME
echo "container $APP_NAME started..."
}
## 停止容器
function stop() {
# 检查容器是否存在
CONTAINER_NAME=$(docker ps | grep "$APP_NAME" | awk '{print $NF}')
# 不存在就不需要停止
if [ -z "$CONTAINER_NAME" ]; then
echo "container $CONTAINER_NAME not running..."
exit 1
fi
# 存在就停止容器
echo "stoping container $APP_NAME..."
docker stop $CONTAINER_NAME
echo "container $APP_NAME stopted..."
}
## 重启容器
function restart() {
# 先停止
stop
# 再启动
start
}
## 删除容器、镜像
function rm() {
# 获取容器名称
CONTAINER_NAME=$(docker ps | grep "$APP_NAME" | awk '{print $NF}')
if [ -n "$CONTAINER_NAME" ]; then
# 停止容器
stop
# 删除容器
echo "removing container $APP_NAME..."
docker rm $CONTAINER_NAME
echo "container $APP_NAME removed..."
fi
# 获取镜像 id
IMAGE=$(docker images | grep "$APP_NAME" | awk '{print $3}')
if [ -n "$IMAGE" ]; then
# 删除镜像
echo "removing image $IMAGE..."
docker rmi $IMAGE
echo "image $IMAGE removed..."
fi
}
# 重新拉取镜像并启动容器
function up() {
# 删除旧的镜像与容器
rm
# 拉取新的镜像并启动容器
start
}
# 根据输入参数,选择执行对应方法,不输入则执行使用说明
case "$COMMAND" in
"up")
up
;;
"start")
start
;;
"stop")
stop
;;
"restart")
restart
;;
"rm")
rm
;;
*)
usage
;;
esac
- 执行脚本
$ chmod +x docker-deploy.sh
$ docker-deploy.sh up
# 查看镜像的情况
$ docker images 10.0.0.51:5000/wolfcode/javaweb-docker-demo:1.0-SNAPSHOT
REPOSITORY TAG IMAGE ID CREATED SIZE
10.0.0.51:5000/wolfcode/javaweb-docker-demo 1.0-SNAPSHOT 227fdd3bad4e 18 minutes ago 680MB
# 查看运行容器的情况
$ docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7ab9e672f40c 10.0.0.51:5000/wolfcode/javaweb-docker-demo:1.0-SNAPSHOT "/bin/sh -c 'bin/cat…" 45 seconds ago Up 44 seconds 0.0.0.0:8808->8080/tcp, :::8808->8080/tcp javaweb-docker-demo
- 访问页面
$ curl 10.0.0.51:8808
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Java Web 项目 Docker 容器化部署</title>
</head>
<body>
<h1>Java Web: Hello Docker!!!</h1>
</body>
</html>
$ curl 10.0.0.51:8808/hello
Java Web: Hello Docker!!!
- IDEA 修改脚本文件中暴露的端口
- 利用
Alibaba Cloud Tookit
的插件将脚本文件进行上传到服务器中,并重新进行package
打包构建镜像
- 利用
Alibaba Cloud Tookit
的插件远程登录到远程服务器中,就可以执行脚本进行运行
# 在服务器中执行脚本docker-deploy.sh
$ bash docker-deploy.sh up
$ curl 10.0.0.51:8808
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Java Web 项目 Docker 容器化部署</title>
</head>
<body>
<h1>Java Web: Hello Docker!!!</h1>
</body>
</html>
$ curl 10.0.0.51:8808/hello
Java Web: Hello Docker!!!
4.2.2.2 部看应用到境像仓库
部署到 ACR
-
在部署参数页面选择
**Alibaba Cloud Container Registry**
。 -
选择
**地域**
、**命名空间**
和**镜像仓库**
。 -
在
**Advanced**
下拉选项中选择网络类型。 -
**Internet**
:公有网络。**VPC Network**
:VPC网络。**Classic Network**
:经典网络。
-
先单击
**Apply**
,然后单击**Run**
。
部看到私服仓库
- 在部署参数页面选择
**Custom Container Registry**
。 - 单击界面右侧的
**Add**
,配置Registry信息。 - 在
**Registry**
页面配置镜像仓库**Name**、**Address**、**Username** 和 **Password**
,单击**Apply**
,然后单击**OK**
。 - 在
**Repository**
对话框填入您的镜像地址。 - 先单击
**Apply**
,然后单击**Run**
。
4.2.2.3 管理远程服务器
添加服务器
已有支持 SSH 协议的远程服务器,可以直接添加;
**添加已有远程服务器**
-
在IntelliJ IDEA顶部菜单栏中选择
**Tools > Alibaba Cloud > Alibaba Cloud View > Host**
。 -
在
**Host**
页签中单击**Add Host**
。 -
在
**Add Host**
对话框填写Host相关信息,然后单击**Test Connection**
来测试是否能成功连接服务器。若成功连接后单击**Add**
。 -
- 添加成功后,远程服务器将出现在
**Host**
页签中。
- 添加成功后,远程服务器将出现在
上传文件
- 在
**Host**
或者**Alibaba Cloud ECS**
页签中单击目标服务器**Actions**
区域的**Upload**
。 - 在
**Upload**
对话框中选择需上传的文件或文件夹,并设置部署参数,然后单击**Upload**
。
下载文件
- 在IntelliJ IDEA菜单栏选择
**Tools > Alibaba Cloud > Alibaba Cloud View > Host**
。 - 在
**Host**
列表右侧**Action**
选择**Remote Files**
。 - 您可根据需求选择刷新、上传和下载远程服务器上的文件。
💫4.3 镜像构建项目实战
4.3.1 Java Web 项目
使用项目地址:
链接:https://pan.baidu.com/s/1nYxMvR9or496BqSh219DCg
提取码:yyds
# 基于 Tomcat9 作为基础镜像
FROM tomcat:9.0
# 作者
MAINTAINER xiaoliu<liugang@wolfcode.cn>
# 进入 Tomcat 部署目录
WORKDIR /usr/local/tomcat/webapps
# 定义参数
ARG JAR_FILE
# 将 war 包拷贝到 tomcat 中,并且改名为 ROOT
COPY ${JAR_FILE} ROOT.war
# 回到 Tomcat 根目录设置工作目录
WORKDIR /usr/local/tomcat/
# 启动时运行命令
CMD bin/catalina.sh run
4.3.2 Spring Boot 项目
可以参考之前章节的过程:
- 4.2.1.1 常见插件
- 4.2.1.2 Dockerfile 配置
- 4.2.1.3 构建镜像
- 4.2.1.4 推送镜像到仓库
使用项目地址:
链接:https://pan.baidu.com/s/1nYxMvR9or496BqSh219DCg
提取码:yyds
## 基础镜像
## AdoptOpenJDK 停止发布 OpenJDK 二进制,而 Eclipse Temurin 是它的延伸,提供更好的稳定性
FROM eclipse-temurin:8-jre
## 作者
MAINTAINER xiaoliu <liugang@wolfcode.cn>
## 定义参数
ARG JAR_FILE
## 创建并进入工作目录
RUN mkdir -p /wolfcode
WORKDIR /wolfcode
## maven 插件构建时得到 buildArgs 种的值
COPY ${JAR_FILE} app.jar
## 设置 TZ 时区
## 设置 JAVA_OPTS 环境变量,可通过 docker run -e "JAVA_OPTS=" 进行覆盖
ENV TZ=Asia/Shanghai JAVA_OPTS="-Xms256m -Xmx256m"
## 暴露端口
EXPOSE 8080
## 容器启动命令
## CMD 第一个参数之后的命令可以在运行时被替换
CMD java ${JAVA_OPTS} -Djava.security.egd=file:/dev/./urandom -jar app.jar
4.3.3 Spring Cloud 微服务项目
使用项目地址:
链接:https://pan.baidu.com/s/1nYxMvR9or496BqSh219DCg
提取码:yyds
项目结构图:
4.3.3.1 部署流程
4.3.3.1.1 容器编排
docker-compose | docker-swarm
4.3.3.1.2 Dockerfile编写
针对每一个服务都需要编写自定义的 Dockerfile,需要对所有服务的 Dockerfile 文件进行一个统一的管理。
4.3.3.1.3 网络问题
自定义网络,或者利用 links 属性,将两个容器连接起来,以上两种方案都可以实现基于容器名称的访问
4.3.3.1.4 日志收集问题
ELK:利用 Lagstash
或 FileBeat
进行数据收集,将数据存入 ES,通过 Kibana
进行统一的数据可视化展示
4.3.3.1.5 监控问题
应用/容器监控,健康状况、资源使用情况都需要进行监控,基于普罗米修斯实现各个类型的监控
4.3.3.2 Cloud Toolkit 最佳实践
项目代码列表
由于是微服务的架构,整体项目结构相对来说是更加复杂的;不可能像之前的单体项目一样,在每一个需要部署的项目里面,比如在 pom.xml 进行添加镜像构建的插件,然后在一边打包一边构建镜像。间接了RuoYi若依
的开源项目。在真正公司开发的时候,更多的讲究效率,能够有现成的脚手架是很不错的选择。
Docker 构建项目结构规划解析
- 将项目的内容和 Docker 相关的 Dockerfile、Docker-Compose 配置文件进行分离。
- docker-compose.yml 是所有容器的一个应用编排管理
- 主要部署的基础设施:mysql(数据库)、nacos(注册中心 | 配置中心)、redis(缓存数据库)
范例:website.conf.nginx.conf
中的 nginx.conf
的文件内容解析
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
# 配置首页的访问路径
location / {
root /home/trip/projects/trip-ui;
# try_files $uri $uri/ /index.html;
index index.html index.htm;
}
# 配置接口的反向代理
location /prod-api/{
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 所有的接口请求都是需要通过网关的
# 所有前端发起请求以后还是请求在nginx上面,nginx基于一个请求路径的一个标识进行反向代理
proxy_pass http://trip-gateway:9000/;
# website 是依赖于 gateway 网关
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
注意:
项目中的配置内容不是固定写法,而是需要结合实际的开发测试生产环境中的需求进行调整
范例:docker-compose.yml
内容的解析
version: '2.4'
services:
trip-nacos: # Nacos 的部署
container_name: trip-nacos # 配置容器名称,方便通过名称来进行网络通信
image: nacos/nacos-server # 使用的镜像
build:
context: ./nacos # 使用 Dockerfile 的上下文环境
environment:
- MODE=standalone # 配置容器的环境变量
volumes: # 数据卷配置
- ./nacos/logs/:/home/nacos/logs
- ./nacos/conf/application.properties:/home/nacos/conf/application.properties
ports: # 暴露的端口(包括健康检测的端口)
- "8848:8848"
- "9848:9848"
- "9849:9849"
depends_on: # 依赖的服务
- trip-mysql
trip-mysql: # MySQL 的部署
container_name: trip-mysql # 配置容器名称,方便通过名称来进行网络通信
image: mysql:5.7 # 使用的镜像
build:
context: ./mysql # 使用 Dockerfile 的上下文环境
ports: # 暴露的端口
- "3306:3306"
volumes: # 数据卷配置
- ./mysql/conf:/etc/mysql/conf.d
- ./mysql/logs:/logs
- ./mysql/data:/var/lib/mysql
command: [ # 容器启动运行的命令
'mysqld',
'--innodb-buffer-pool-size=80M',
'--character-set-server=utf8mb4',
'--collation-server=utf8mb4_unicode_ci',
'--default-time-zone=+8:00',
'--lower-case-table-names=1'
]
environment: # 配置容器的环境变量
MYSQL_DATABASE: 'trip-cloud'
MYSQL_ROOT_PASSWORD: 'admin'
trip-redis: # Redis 的部署
container_name: trip-redis # 配置容器名称,方便通过名称来进行网络通信
image: redis # 使用的镜像
build:
context: ./redis # 使用 Dockerfile 的上下文环境
ports: # 暴露的端口
- "6379:6379"
volumes: # 数据卷配置
- ./redis/conf/redis.conf:/home/trip/redis/redis.conf
- ./redis/data:/data
command: redis-server /home/trip/redis/redis.conf # 容器启动运行的命令
trip-website: # Nginx 的部署
container_name: trip-website # 配置容器名称,方便通过名称来进行网络通信
image: nginx # 使用的镜像
build:
context: ./website # 使用 Dockerfile 的上下文环境
ports: # 暴露的端口
- "80:80"
volumes: # 数据卷配置
- ./website/html/dist:/home/trip/projects/trip-ui
- ./website/conf/nginx.conf:/etc/nginx/nginx.conf
- ./website/logs:/var/log/nginx
- ./website/conf.d:/etc/nginx/conf.d
depends_on: # 依赖的服务
- trip-gateway
links: # links 关联的服务,可以使用容器的主机名进行通信
- trip-gateway
trip-gateway: # 网关服务
container_name: trip-gateway # 配置容器名称,方便通过名称来进行网络通信
build: # 使用 Dockerfile 的上下文环境
context: ./trip/gateway
dockerfile: dockerfile
ports: # 暴露的端口
- "9000:9000"
depends_on: # 依赖的服务
- trip-redis
links: # links 关联的服务,可以使用容器的主机名进行通信
- trip-redis
trip-user: # 用户服务
container_name: trip-user # 配置容器名称,方便通过名称来进行网络通信
build: # 使用 Dockerfile 的上下文环境
context: ./trip/user
dockerfile: dockerfile
ports: # 暴露的端口
- "9200:9200"
depends_on: # 依赖的服务
- trip-redis
- trip-mysql
links: # links 关联的服务,可以使用容器的主机名进行通信
- trip-redis
- trip-mysql
trip-article: # 文章服务
container_name: trip-article # 配置容器名称,方便通过名称来进行网络通信
build: # 使用 Dockerfile 的上下文环境
context: ./trip/article
dockerfile: dockerfile
ports: # 暴露的端口
- "8060:8060"
depends_on: # 依赖的服务
- trip-redis
- trip-mysql
- trip-user
links: # links 关联的服务,可以使用容器的主机名进行通信
- trip-redis
- trip-mysql
- trip-user
--link
和 Docker-Compose 中的 links
的参数会在后期被 Docker 遗弃。
官方文档:https://docs.docker.com/compose/compose-file/compose-file-v3/#links
4.3.3.2.1 部署微服务多模块
需要将整个项目的配置文件和资料要准备好
微服务项目的部署流程:
- SpringBoot 的项目需要添加依赖
- 使用
Alibaba Cloud Toolkit
插件上传项目代码
- 运行
deploy.sh
脚本信息
# 部署基础设施服务
$ sh deploy.sh base
$ docker-compose ps
Name Command State Ports
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
trip-mysql docker-entrypoint.sh mysql ... Up 0.0.0.0:3306->3306/tcp,:::3306->3306/tcp, 33060/tcp
trip-nacos bin/docker-startup.sh Up 0.0.0.0:8848->8848/tcp,:::8848->8848/tcp, 0.0.0.0:9848->9848/tcp,:::9848->9848/tcp, 0.0.0.0:9849->9849/tcp,:::9849->9849/tcp
trip-redis docker-entrypoint.sh redis ... Up 0.0.0.0:6379->6379/tcp,:::6379->6379/tcp
# 需要前提解压website中的html.zip的压缩包
$ unzip html.zip
# 部署启动应用程序模块
$ sh deploy.sh services
$ docker-compose ps
Name Command State Ports
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
trip-article java -jar trip-article.jar Up 0.0.0.0:8060->8060/tcp,:::8060->8060/tcp
trip-gateway java -jar trip-gateway.jar Up 0.0.0.0:9000->9000/tcp,:::9000->9000/tcp
trip-mysql docker-entrypoint.sh mysql ... Up 0.0.0.0:3306->3306/tcp,:::3306->3306/tcp, 33060/tcp
trip-nacos bin/docker-startup.sh Up 0.0.0.0:8848->8848/tcp,:::8848->8848/tcp, 0.0.0.0:9848->9848/tcp,:::9848->9848/tcp, 0.0.0.0:9849->9849/tcp,:::9849->9849/tcp
trip-redis docker-entrypoint.sh redis ... Up 0.0.0.0:6379->6379/tcp,:::6379->6379/tcp
trip-user java -jar trip-user.jar Up 0.0.0.0:9200->9200/tcp,:::9200->9200/tcp
trip-website /docker-entrypoint.sh ngin ... Up 0.0.0.0:80->80/tcp,:::80->80/tcp
通过浏览器访问服务器IP地址
,就可以查看到相应的微服务项目
4.3.3.2.2 查看远程日志
docker-compose logs [服务名]
docker-compose logs -f [服务名]
学技术不能太钻牛角尖,要从深度和广度两个方面是去来看待学习