yyy

Drone 部署 Spring boot 服务多环境配置

环境准备

流程

流程图

mermaid
mermaid
graph TB
st(开始)
e(结束)
st-->push(提交代码)
st-->tag(提交 Tag)
push-->op1(Maven 打包项目 生成 Jar 包文件)
tag-->op1
op1-->condService(是否是服务)
condService-->|否|sub1(发布 Jar 包到私服仓库)
condService-->|是|condTag("构建发布镜像")
condTag-->|是|op2(发布 Git 版本)
condTag-->|否|op3(拷贝 docker-compose.yml 到目标服务器)
op2-->op3
op3-->op4(连接目标服务器运行)
sub1-->e
op4-->e

环境配置

Maven 配置

开发过程中可能回有多个 Java 版本的情况,以及会使用一些代理仓库加速下载依赖,构建一些内部常用的 Maven 环境

本文以 eclipse-temurin-8-alpine 为例,GitHub 查看更多版本

下载 Dockerfilemvn-entrypoint.sh 文件,

Terminal window
wget https://raw.githubusercontent.com/carlossg/docker-maven/master/eclipse-temurin-8-alpine/Dockerfile
wget https://raw.githubusercontent.com/carlossg/docker-maven/master/eclipse-temurin-8-alpine/mvn-entrypoint.sh

settings.xml 添加自定义设置文件

settings.xml
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
https://maven.apache.org/xsd/settings-1.0.0.xsd">
<localRepository>/usr/share/maven/ref/repository</localRepository>
<servers>
<server>
<id>private-repo</id> <!-- 仓库 ID,与 pom.xml 中配置的 repository id 匹配 -->
<username>your-username</username>
<password>your-password</password>
</server>
</servers>
<mirrors>
<mirror>
<id>mirror-repo</id>
<mirrorOf>*</mirrorOf>
<name>mirror repo</name>
<url>http://nexus.domain.com/repository/maven-mirror-repo/</url>
</mirror>
</mirrors>
<profiles>
<profile>
<id>private-repo-profile</id>
<repositories>
<repository>
<id>private-repo</id> <!-- 仓库 ID,与 servers 中的 id 匹配 -->
<url>http://nexus.domain.com/repository/maven-private-repo/</url>
<releases><enabled>true</enabled></releases>
<snapshots><enabled>true</enabled></snapshots>
</repository>
</repositories>
</profile>
</profiles>
<activeProfiles>
<activeProfile>private-repo-profile</activeProfile>
</activeProfiles>
</settings>

修改 Dockerfile

Dockerfile
FROM eclipse-temurin:8-jdk-alpine
# 国内网络问题,使用 aliyun 源
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
RUN apk add --no-cache curl tar bash procps
# ...
COPY mvn-entrypoint.sh /usr/local/bin/mvn-entrypoint.sh
# 添加自定义配置文件
COPY settings.xml /usr/share/maven/conf/
ENTRYPOINT ["/usr/local/bin/mvn-entrypoint.sh"]
CMD ["mvn"]

打包成镜像

Terminal window
docker build -t ci/maven:8-jdk .

配置部署模板文件

生成 Dockerfile,docker-compose.yml 等文件相关脚本,可以更具自己实际需求更改

Dockerfile.tmpl

Dockerfile.tmpl
FROM <% ${FROM_IMAGE} %>
ADD <% ${SERVICE_JAR} %> app.jar
ENTRYPOINT ["java", "-Duser.timezone=GMT+08","-jar", "/app.jar" <% ${SERVICE_PARAMS} %> ]

docker-compose.yml.tmpl

docker-compose.yml.tmpl
version: '3'
services:
<% ${SERVICE_NAME} %>:
restart: always
image: <% ${SERVICE_IMAGE_NAME} %>:<% ${vTag} %>
container_name: <% ${SERVICE_NAME} %>
ports: # - <% ${SERVICE_PORT} %>:<% ${SERVICE_PORT} %> 可能多个情况使用sed插入
deploy:
resources:
limits:
memory: <% ${SERVICE_MEMORY} %>

convert_param.sh:构造 Dockerfile 中 SERVICE_PARAMS 参数

convert_param.sh
#!/bin/bash
params=""
d=","
paramCount=$#
for (( i = 1; i <= paramCount; i++ )); do
params="$params $d \\"\"${!i}\\"\""
done
echo "$params"

template.sh:使用环境参数生成文件

template.sh
#!/bin/sh
EOF=EOF
exec cat <<EOF | sh
cat <<EOF
$(cat $1 | \
sed 's|`|\\`|g' | \
sed 's|\$|\\\$|g' | \
sed "s|${OPEN:-<%}|\`eval echo |g" | \
sed "s|${CLOSE:-%>}|\`|g")
$EOF
EOF

使用

Terminal window
# 查看
sh template.sh Dockerfile.tmpl
# 使用生成
sh template.sh Dockerfile.tmpl > Dockerfile

配置 Drone 模板

mvn-deploy.yml:Maven 打包私服模板,工具类等不需要部署的项目

mvn-deploy.yml
kind: pipeline # 定义对象类型,还有secret和signature两种类型
type: docker # 定义流水线类型,还有kubernetes、exec、ssh等类型
name: default # 定义流水线名称
steps: # 定义流水线执行步骤,这些步骤将顺序执行
- name: mvn-deploy # 流水线名称
pull: if-not-exists
image: {{ .input.buildImage }} # 定义创建容器的Docker镜像
network_mode: host
volumes: # 将容器内目录挂载到宿主机,仓库需要开启Trusted设置
- name: maven-cache
path: /usr/share/maven/ref/repository # 这个需要 Maven settings.xml 中一致
commands:
- mvn clean deploy
volumes: # 定义流水线挂载目录,用于共享数据
- name: maven-cache
host:
path: /data/maven/cache # 主机目录缓存依赖
trigger:
event:
- push

mvn-build-push-image-run.yaml:Maven 打包部署模板

mvn-build-push-image-run.yaml
kind: pipeline
type: docker
name: mvn-build-push-image-run-start
steps:
- name: mvn-build
pull: if-not-exists
image: {{ .input.buildImage }}
network_mode: host
volumes:
- name: maven-cache
path: /usr/share/maven/ref/repository
- name: ci-env
path: /app/ci-env
commands: # 定义在Docker容器中执行的shell命令
- mvn clean package
- rm target/*sources.jar && cp target/*.jar . && cp /app/ci-env/* .
- chmod +x template.sh convert_param.sh
- export vTag=`ls *.jar | awk -F {{ .input.name }}- '{print $2}' | awk -F .jar '{print $1}'`
- export SERVICE_JAR=`ls *.jar`
- export SERVICE_PARAMS=`./convert_param.sh {{ range .input.deploy.params }} {{ . }}{{ end }}`
- sh template.sh Dockerfile.tmpl > Dockerfile
- sh template.sh docker-compose.yml.tmpl > docker-compose.yml
- sed -i '5i\{{ range .input.ports }}EXPOSE {{ . }}\n{{ end }}' Dockerfile
- sed -i '8i\{{ range .input.ports }} - {{ . }}:{{ . }}\n{{ end }}' docker-compose.yml
- echo -n $vTag,latest > .tags
environment:
FROM_IMAGE: {{ .input.deploy.fromImage }}
SERVICE_NAME: {{ .input.name }}
SERVICE_MEMORY: {{ .input.memory }}
SERVICE_IMAGE_NAME: {{ .input.image.registry }}/{{ .input.image.name }}
83 collapsed lines
- name: push-image
pull: if-not-exists
image: plugins/docker
network_mode: host
settings:
registry: {{ .input.image.registry }} # if not provided index.docker.io is supposed
repo: {{ .input.image.registry }}/{{ .input.image.name }}
cache: true
username:
from_secret: {{ .input.image.docker_username_key }}
password:
from_secret: {{ .input.image.docker_password_key }}
- name: gitea release
image: plugins/gitea-release
pull: if-not-exists
network_mode: host
settings:
api_key:
from_secret: git_release
prerelease: true
base_url: https://git.domain.com
title: ${DRONE_TAG}
files:
- ./*.jar
- ./*docker-compose.yml
- ./*Dockerfile
checksum:
- md5
- sha1
when:
event: tag
- name: scp files
image: appleboy/drone-scp
pull: if-not-exists
settings:
host: dev.domain.com # 远程连接地址
port: 22 # 远程连接端口
username: root # 远程连接账号
password:
from_secret: dev_password # 从Secret中读取SSH密码
target: {{ .input.workdir }}
overwrite: true
source:
- docker-compose.yml
- name: run-start
pull: if-not-exists
network_mode: host
image: appleboy/drone-ssh # SSH工具镜像
settings:
host: dev.domain.com # 远程连接地址
port: 22 # 远程连接端口
username: root # 远程连接账号
password:
from_secret: dev_password # 从Secret中读取SSH密码
command_timeout: 5m # 远程执行命令超时时间
envs:
- DOCKER_USERNAME
- DOCKER_PASSWORD
script:
- cd {{ .input.workdir }}
- echo "$DOCKER_PASSWORD" | docker login {{ .input.image.registry }} -u $DOCKER_USERNAME --password-stdin
- docker-compose down && docker-compose pull && docker-compose up -d
environment:
DOCKER_USERNAME:
from_secret: {{ .input.image.docker_username_key }}
DOCKER_PASSWORD:
from_secret: {{ .input.image.docker_password_key }}
volumes: # 定义流水线挂载目录,用于共享数据
- name: maven-cache
host:
path: /data/maven/cache
- name: ci-env
host:
path: /data/ci-env
trigger:
event:
- push
- tag

编写 .drone.yml 脚本

.drone.yml
kind: template
load: mvn-build-push-image-run.yaml
name: mvn-build-push-image-run
data:
name: drone-demo # 这里需要注意需要和 Jar 包名一致,drone-demo-0.0.1.jar
ports:
- 8080
# - 9090
memory: 1G
workdir: /data/service/drone-demo
buildImage: ci/maven:8-jdk
image:
registry: harbor.domain.com
name: service/drone-demo
# docker 用户名密码前缀 需要 secrets 添加 xxx_docker_username
docker_username_key: docker_username
docker_password_key: docker_password
# Dockerfile 配置
deploy:
fromImage: eclipse-temurin:8-jdk
params:
- --spring.profiles.active=dev
#drone #spring