SpringCloudAlibaba微服务docker容器打包和部署示例实战 - itxiaoshen
source link: https://www.cnblogs.com/itxiaoshen/p/16167851.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
我们使用前面《SpringCloudAlibaba注册中心与配置中心之利器Nacos实战与源码分析(中)》的两个微服务示例,分别是库存微服务和订单微服务,基于Nacos注册中心和配置中心的使用,前面Nacos我们已基于dock-compose方式部署,我们增加配置数据,这里我们暂时也不把数据打包进去,各位可以直接将容器以dokcer export方式导入为镜像,微服务使用订单、库存MySQL数据库暂时也不单独做成镜像,各位可以做成SQL脚本执行导入方式。
整体工程结构
- docker目录docker compose编排脚本目录
- bin目录:包含初始化脚本、启动脚本、停止脚本、更新脚本
- env目录:存在为微服务环境变量
- yaml目录:存在全局环境脚本变量、微服务docker-compose脚本
- 库存微服务
- bin目录:存在微服务启动脚本
- conf目录:存在启动配置文件和日志配置文件
- Dockerfile文件
- 订单微服务
- bin目录:存在微服务启动脚本
- conf目录:存在启动配置文件和日志配置文件
- Dockerfile文件
库存微服务
编写配置文件
bootstrap.yml
spring:
application:
name: ecom-storage-service
profiles:
active: ${SPRING_PROFILES_ACTIVE:"dev"}
main:
allow-circular-references: true
cloud:
nacos:
# 注册中心信息放在配置中心上,每个程序一般只配置配置中心的信息
server-addr: ${NACOS_CONFIG_SERVER:"192.168.50.95:8848"}
config:
server-addr: ${spring.cloud.nacos.server-addr}
file-extension: yaml
namespace: ${NACOS_CONFIG_NAMESPACE:"a2b1a5b7-d0bc-48e8-ab65-04695e61db01"}
group: ${NACOS_CONFIG_GROUP:"storage-group"}
extension-configs:
- dataId: extension-priority-dev.yaml
group: extension-group
refresh: true
- dataId: commons-dev.yaml
group: commons-group
refresh: true
shared-configs:
- dataId: shared-priority-dev.yaml
group: shared-group
refresh: true
username: itsx
password: itxs123
enabled: true # 默认为true,设置false 来完全关闭 Spring Cloud Nacos Config
refresh-enabled: true # 默认为true,当变更配置时,应用程序中能够获取到最新的值,设置false来关闭动态刷新,我们使用注册中心场景大部分就是动态感知,因此基本使用默认的
logback.xml
<?xml version="1.0" encoding="UTF-8" ?>
<configuration debug="false">
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
<springProperty scope="context" name="APP_HOME" source="spring.application.name"/>
<property name="LOG_HOME" value="${LOG_PATH:-.}" />
<!-- 控制台输出设置 -->
<!-- 彩色日志格式,magenta:洋红,boldMagenta:粗红,yan:青色,·⊱══> -->
<property name="CONSOLE_LOG_PATTERN" value="%boldMagenta([%d{yyyy-MM-dd HH:mm:ss.SSS}]) %cyan([%X{requestId}]) %boldMagenta(%-5level) %blue(%logger{15}) %red([%thread]) %magenta(·⊱══>) %cyan(%msg%n)"/>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
<charset>utf8</charset>
</encoder>
</appender>
<!-- 按天输出日志设置 -->
<appender name="DAY_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件输出的文件名 -->
<FileNamePattern>${LOG_HOME}/%d{yyyy-MM-dd}_${APP_HOME}.%i.log</FileNamePattern>
<!-- 日志文件保留天数 -->
<MaxHistory>7</MaxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>50MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level> <!-- 设置拦截的对象为INFO级别日志 -->
<onMatch>ACCEPT</onMatch> <!-- 当遇到了INFO级别时,启用改段配置 -->
<onMismatch>DENY</onMismatch> <!-- 没有遇到INFO级别日志时,屏蔽改段配置 -->
</filter>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!-- 格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符 -->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<!-- 按天输出WARN级别日志设置 -->
<appender name="DAY_WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件输出的文件名 -->
<FileNamePattern>${LOG_HOME}/%d{yyyy-MM-dd}_${APP_HOME}_warn.%i.log</FileNamePattern>
<!-- 日志文件保留天数 -->
<MaxHistory>7</MaxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>50MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>WARN</level> <!-- 设置拦截的对象为INFO级别日志 -->
<onMatch>ACCEPT</onMatch> <!-- 当遇到了INFO级别时,启用改段配置 -->
<onMismatch>DENY</onMismatch> <!-- 没有遇到INFO级别日志时,屏蔽改段配置 -->
</filter>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!-- 格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符 -->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<!-- 按天输出ERROR级别日志设置 -->
<appender name="DAY_ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件输出的文件名 -->
<FileNamePattern>${LOG_HOME}/%d{yyyy-MM-dd}_${APP_HOME}_error.%i.log</FileNamePattern>
<!-- 日志文件保留天数 -->
<MaxHistory>7</MaxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>50MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level> <!-- 设置拦截的对象为ERROR级别日志 -->
<onMatch>ACCEPT</onMatch> <!-- 当遇到了ERROR级别时,启用改段配置 -->
<onMismatch>DENY</onMismatch> <!-- 没有遇到ERROR级别日志时,屏蔽改段配置 -->
</filter>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!-- 格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符 -->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<!-- 日志输出级别,OFF level > FATAL > ERROR > WARN > INFO > DEBUG > ALL level -->
<logger name="com.sand" level="INFO"/>
<logger name="com.apache.ibatis" level="INFO"/>
<logger name="java.sql.Statement" level="INFO"/>
<logger name="java.sql.Connection" level="INFO"/>
<logger name="java.sql.PreparedStatement" level="INFO"/>
<logger name="org.springframework" level="WARN"/>
<logger name="com.baomidou.mybatisplus" level="WARN"/>
<!-- 开发环境:打印控制台和输出到文件 -->
<springProfile name="dev">
<root level="INFO">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="DAY_FILE"/>
<appender-ref ref="DAY_WARN_FILE"/>
<appender-ref ref="DAY_ERROR_FILE"/>
</root>
</springProfile>
<!-- 生产环境:打印控制台和输出到文件 -->
<springProfile name="pro">
<root level="INFO">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="DAY_FILE"/>
<appender-ref ref="DAY_WARN_FILE"/>
<appender-ref ref="DAY_ERROR_FILE"/>
</root>
</springProfile>
</configuration>
制作Docker启动脚本
docker-startup.sh
#!/bin/bash
set -x
export CUSTOM_SEARCH_NAMES="application,custom"
export CUSTOM_SEARCH_LOCATIONS=${BASE_DIR}/init.d/,file:${BASE_DIR}/conf/
JAVA_OPT="${JAVA_OPT} -Dsimple_ecommerce.home=${BASE_DIR}"
JAVA_OPT="${JAVA_OPT} -jar ${BASE_DIR}/target/ecom-storage-service.jar"
JAVA_OPT="${JAVA_OPT} ${JAVA_OPT_EXT}"
JAVA_OPT="${JAVA_OPT} --spring.config.additional-location=${CUSTOM_SEARCH_LOCATIONS}"
JAVA_OPT="${JAVA_OPT} --spring.config.name=${CUSTOM_SEARCH_NAMES}"
JAVA_OPT="${JAVA_OPT} --logging.config=${BASE_DIR}/conf/logback.xml"
JAVA_OPT="${JAVA_OPT} --logging.file.path=${BASE_DIR}/logs/"
JAVA_OPT="${JAVA_OPT} --spring.config.location=${BASE_DIR}/conf/bootstrap.yml"
JAVA_OPT="${JAVA_OPT} --server.max-http-header-size=524288"
echo "ecom-storage-service is starting, you can docker logs your container"
exec $JAVA ${JAVA_OPT}
制作Dockerfile文件
Dockerfile文件
FROM java:8
MAINTAINER itxs "[email protected]"
ARG ECOM_STORAGE_SERVICE_VERSION=1.0
ARG ECOM_STORAGE_SERVICE_DIR="ecom-storage-service"
ARG ECOM_STORAGE_SERVICE_PACKAGE="ecom-storage-service-$ECOM_STORAGE_SERVICE_VERSION.jar"
ARG ECOM_STORAGE_SERVICE_PROGRAM="ecom-storage-service.jar"
# set environment
ENV BASE_DIR="/home/simple_ecommerce/${ECOM_STORAGE_SERVICE_DIR}" \
CLASSPATH=".:/home/simple_ecommerce/${ECOM_STORAGE_SERVICE_DIR}/conf:$CLASSPATH" \
JAVA_HOME="/usr/lib/jvm/java-8-openjdk-amd64" \
JAVA="/usr/lib/jvm/java-8-openjdk-amd64/bin/java" \
JAVA_OPT_EXT="${JAVA_OPT_EXT}" \
TIME_ZONE="Asia/Shanghai"
WORKDIR $BASE_DIR
ADD ./target/$ECOM_STORAGE_SERVICE_PACKAGE target/$ECOM_STORAGE_SERVICE_PROGRAM
RUN ln -snf /usr/share/zoneinfo/$TIME_ZONE /etc/localtime && echo $TIME_ZONE > /etc/timezone
ADD bin/docker-startup.sh bin/docker-startup.sh
ADD conf/bootstrap.yml conf/bootstrap.yml
ADD conf/logback.xml conf/logback.xml
RUN mkdir -p init.d
# set startup log dir
RUN mkdir -p logs \
&& cd logs \
&& touch start.out \
&& ln -sf /dev/stdout start.out \
&& ln -sf /dev/stderr start.out
RUN chmod +x bin/docker-startup.sh
EXPOSE 4080
ENTRYPOINT ["bin/docker-startup.sh"]
库存微服务pom文件添加docker-maven-plugin
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>simple-ecommerce</artifactId>
<groupId>cn.itxs</groupId>
<version>1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ecom-storage-service</artifactId>
<packaging>jar</packaging>
<version>1.0</version>
<name>ecom-storage-service</name>
<description>a simple electronic commerce platform demo tutorial for storage service</description>
<dependencies>
<dependency>
<groupId>cn.itxs</groupId>
<artifactId>ecom-commons</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<!-- 指定该Main Class为全局的唯一入口 -->
<mainClass>cn.itxs.ecom.storage.StorageServiceApplication</mainClass>
<layout>ZIP</layout>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal><!--可以把依赖的包都打包到生成的Jar包中-->
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>0.39.1</version>
<configuration>
<authConfig>
<!-- registry服务的认证-->
<username>admin</username>
<password>admin12345</password>
</authConfig>
<images>
<image>
<!-- 指定image的名字(包含registry地址)-->
<name>simple_ecommerce/${project.name}:${project.version}</name>
<!--registry地址,用于推送,拉取镜像-->
<registry>registry.itxs.cn</registry>
<!-- 别名为master,不关键-->
<alias>master</alias>
<build>
<!-- 指定dockerfile文件的位置-->
<dockerFile>${project.basedir}/Dockerfile</dockerFile>
<buildOptions>
<!-- 网络的配置,与宿主主机共端口号-->
<network>host</network>
</buildOptions>
</build>
</image>
</images>
</configuration>
<executions>
<execution>
<id>docker-exec</id>
<!-- 绑定mvn install阶段,当执行mvn install时 就会执行docker build 和docker push-->
<phase>install</phase>
<goals>
<goal>build</goal>
<goal>push</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
可以看到库存微服务pom文件添加docker-maven-plugin,mvn install阶段,当执行mvn install时 就会执行docker build 和docker push,我们前面也介绍Docker Harbor私有仓库的部署,可以通过插件直接推送内网的Harbor私有仓库里。
订单微服务
编写配置文件
bootstrap.yml
spring:
application:
name: ecom-order-service
profiles:
active: dev
main:
allow-circular-references: true
cloud:
# 负载均衡器缓存
loadbalancer:
cache:
enabled: true
caffeine:
spec: initialCapacity=500,expireAfterWrite=5s
nacos:
# 注册中心信息放在配置中心上,每个程序一般只配置配置中心的信息
server-addr: ${NACOS_CONFIG_SERVER:"192.168.50.95:8848"}
config:
server-addr: ${spring.cloud.nacos.server-addr}
file-extension: yaml
namespace: ${NACOS_CONFIG_NAMESPACE:"a2b1a5b7-d0bc-48e8-ab65-04695e61db01"}
group: ${NACOS_CONFIG_GROUP:"order-group"}
username: itsx
password: itxs123
extension-configs:
- dataId: commons-dev.yaml
group: commons-group
refresh: true
enabled: true # 默认为true,设置false 来完全关闭 Spring Cloud Nacos Config
refresh-enabled: true # 默认为true,当变更配置时,应用程序中能够获取到最新的值,设置false来关闭动态刷新,我们使用注册中心场景大部分就是动态感知,因此基本使用默认的
制作Docker启动脚本
docker-startup.sh
#!/bin/bash
set -x
export CUSTOM_SEARCH_NAMES="application,custom"
export CUSTOM_SEARCH_LOCATIONS=${BASE_DIR}/init.d/,file:${BASE_DIR}/conf/
JAVA_OPT="${JAVA_OPT} -Dsimple_ecommerce.home=${BASE_DIR}"
JAVA_OPT="${JAVA_OPT} -jar ${BASE_DIR}/target/ecom-order-service.jar"
JAVA_OPT="${JAVA_OPT} ${JAVA_OPT_EXT}"
JAVA_OPT="${JAVA_OPT} --spring.config.additional-location=${CUSTOM_SEARCH_LOCATIONS}"
JAVA_OPT="${JAVA_OPT} --spring.config.name=${CUSTOM_SEARCH_NAMES}"
JAVA_OPT="${JAVA_OPT} --logging.config=${BASE_DIR}/conf/logback.xml"
JAVA_OPT="${JAVA_OPT} --logging.file.path=${BASE_DIR}/logs/"
JAVA_OPT="${JAVA_OPT} --spring.config.location=${BASE_DIR}/conf/bootstrap.yml"
JAVA_OPT="${JAVA_OPT} --server.max-http-header-size=524288"
echo "ecom-order-service is starting, you can docker logs your container"
exec $JAVA ${JAVA_OPT}
制作Dockerfile文件
Dockerfile文件
FROM java:8
MAINTAINER itxs "[email protected]"
ARG ECOM_ORDER_SERVICE_VERSION=1.0
ARG ECOM_ORDER_SERVICE_DIR="ecom-order-service"
ARG ECOM_ORDER_SERVICE_PACKAGE="ecom-order-service-$ECOM_ORDER_SERVICE_VERSION.jar"
ARG ECOM_ORDER_SERVICE_PROGRAM="ecom-order-service.jar"
# set environment
ENV BASE_DIR="/home/simple_ecommerce/${ECOM_ORDER_SERVICE_DIR}" \
CLASSPATH=".:/home/simple_ecommerce/${ECOM_ORDER_SERVICE_DIR}/conf:$CLASSPATH" \
JAVA_HOME="/usr/lib/jvm/java-8-openjdk-amd64" \
JAVA="/usr/lib/jvm/java-8-openjdk-amd64/bin/java" \
JAVA_OPT_EXT="${JAVA_OPT_EXT}" \
TIME_ZONE="Asia/Shanghai"
WORKDIR $BASE_DIR
ADD ./target/$ECOM_ORDER_SERVICE_PACKAGE target/$ECOM_ORDER_SERVICE_PROGRAM
RUN ln -snf /usr/share/zoneinfo/$TIME_ZONE /etc/localtime && echo $TIME_ZONE > /etc/timezone
ADD bin/docker-startup.sh bin/docker-startup.sh
ADD conf/bootstrap.yml conf/bootstrap.yml
ADD conf/logback.xml conf/logback.xml
RUN mkdir -p init.d
# set startup log dir
RUN mkdir -p logs \
&& cd logs \
&& touch start.out \
&& ln -sf /dev/stdout start.out \
&& ln -sf /dev/stderr start.out
RUN chmod +x bin/docker-startup.sh
EXPOSE 4070
ENTRYPOINT ["bin/docker-startup.sh"]
订单微服务pom文件添加docker-maven-plugin
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>simple-ecommerce</artifactId>
<groupId>cn.itxs</groupId>
<version>1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ecom-order-service</artifactId>
<packaging>jar</packaging>
<version>1.0</version>
<name>ecom-order-service</name>
<description>a simple electronic commerce platform demo tutorial for order service</description>
<dependencies>
<dependency>
<groupId>cn.itxs</groupId>
<artifactId>ecom-commons</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>3.0.6</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<!-- 指定该Main Class为全局的唯一入口 -->
<mainClass>cn.itxs.ecom.order.OrderServiceApplication</mainClass>
<layout>ZIP</layout>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal><!--可以把依赖的包都打包到生成的Jar包中-->
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>0.39.1</version>
<configuration>
<authConfig>
<!-- registry服务的认证-->
<username>admin</username>
<password>admin12345</password>
</authConfig>
<images>
<image>
<!-- 指定image的名字(包含registry地址)-->
<name>simple_ecommerce/${project.name}:${project.version}</name>
<!--registry地址,用于推送,拉取镜像-->
<registry>registry.itxs.cn</registry>
<!-- 别名为master,不关键-->
<alias>master</alias>
<build>
<!-- 指定dockerfile文件的位置-->
<dockerFile>${project.basedir}/Dockerfile</dockerFile>
<buildOptions>
<!-- 网络的配置,与宿主主机共端口号-->
<network>host</network>
</buildOptions>
</build>
</image>
</images>
</configuration>
<executions>
<execution>
<id>docker-exec</id>
<!-- 绑定mvn install阶段,当执行mvn install时 就会执行docker build 和docker push-->
<phase>install</phase>
<goals>
<goal>build</goal>
<goal>push</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
上面订单微服务pom文件添加docker-maven-plugin,mvn install阶段,当执行mvn install时 就会执行docker build 和docker push,我们前面也介绍Docker Harbor私有仓库的部署,可以通过插件直接推送内网的Harbor私有仓库里。
# 由于需要进行docker build 和docker push,打包机器需要安装docker,直接执行mvn clean install 即可,如果需要单独mvn clean install# 如果是单独针对库存微服务只进行docker build,可以进入库存微服务目录mvn clean package docker:bulid
docker build两个微服务的镜像文件如下,这个是我单独docker build没有push.如果install的话上传内网Harbor仓库本地先生成镜像,然后再上传最后删除本地的镜像。
env目录
订单微服务环境变量ecom-order-service.env,这里NACOS_CONFIG_SERVER简单先用地址,如果是在单个宿主机或者K8s环境下,并且在同个容器网络内可以直接使用容器名,可不需要Nacos地址配置,这里我们就先用暴露宿主机端口,先重点放在两个微服务容器上。
SPRING_PROFILES_ACTIVE=dev
NACOS_CONFIG_SERVER=192.168.50.95:8848
NACOS_CONFIG_NAMESPACE=a2b1a5b7-d0bc-48e8-ab65-04695e61db01
NACOS_CONFIG_GROUP=order-group
JAVA_OPT_EXT="-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xms1024m -Xmx1024m -Xmn1024m -XX:-UseAdaptiveSizePolicy -XX:SurvivorRatio=4 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:-CMSConcurrentMTEnabled -XX:CMSInitiatingOccupancyFraction=70 -XX:+CMSParallelRemarkEnabled -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=256m"
库存微服务环境变量ecom-storage-service.env
SPRING_PROFILES_ACTIVE=dev
NACOS_CONFIG_SERVER=192.168.50.95:8848
NACOS_CONFIG_NAMESPACE=a2b1a5b7-d0bc-48e8-ab65-04695e61db01
NACOS_CONFIG_GROUP=storage-group
JAVA_OPT_EXT="-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xms1024m -Xmx1024m -Xmn1024m -XX:-UseAdaptiveSizePolicy -XX:SurvivorRatio=4 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:-CMSConcurrentMTEnabled -XX:CMSInitiatingOccupancyFraction=70 -XX:+CMSParallelRemarkEnabled -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=256m"
制作Docker-Compose编排文件
我这里做法没有将多个微服务编排的一个Docker-Compose文件里,而已单独做一个Docker-Compose,通过shell脚本串联起来执行,各位也可以直接编写一个Docker-Compose
全局环境变量.env存放全局参数信息,例如各微服务的版本信息
ECOM_STORAGE_VERSION=1.0ECOM_ORDER_VERSION=1.0
库存微服务Docker-Compose文件ecom-storage-service.yml,如果是本地build则image去掉registry.itxs.cn/
version: "3"
services:
ecom-storage-service:
image: registry.itxs.cn/simple_ecommerce/ecom-storage-service:${ECOM_STORAGE_VERSION}
container_name: ecom-storage-service
env_file:
- ../env/ecom-storage-service.env
volumes:
- ../logs/ecom-storage-service/:/home/simple_ecommerce/ecom-storage-service/logs
ports:
- "4080:4080"
networks:
- simple_ecommerce
restart: always
networks:
simple_ecommerce:
external: true
订单微服务Docker-Compose文件ecom-order-service.yml
version: "3"
services:
ecom-order-service:
image: registry.itxs.cn/simple_ecommerce/ecom-order-service:${ECOM_ORDER_VERSION}
container_name: ecom-order-service
env_file:
- ../env/ecom-order-service.env
volumes:
- ../logs/ecom-order-service/:/home/simple_ecommerce/ecom-order-service/logs
ports:
- "4070:4070"
networks:
- simple_ecommerce
restart: always
networks:
simple_ecommerce:
external: true
bin目录下我们创建操作脚本,init.sh初始化检查环境、安装docker和docker-compose、
#!/usr/bin/env bash
echo "############当前操作系统版本##############"
if ! type yum >/dev/null 2>&1; then
echo "【ERROR】目前脚本仅支持CentOS7.X系统"
exit 8
else
osVersion=$(echo `cat /etc/redhat-release | sed -r 's/.* ([0-9]+)\..*/\1/'`)
if [[ "$osVersion" != "7" ]]; then
echo "【ERROR】目前脚本仅支持CentOS7.X系统"
exit 8
else
echo '版本校验成功'
fi
fi
echo "############判断是否安装了docker##############"
if ! type docker >/dev/null 2>&1; then
echo 'docker 未安装';
echo '开始安装Docker....';
yum install -y yum-utils
yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
#安装docker核心引擎、命令行客户端、容器
yum install docker-ce docker-ce-cli containerd.io
echo 'docker 安装完毕';
#启动docker
echo '配置Docker开启启动';
systemctl enable docker
systemctl start docker
cat >> /etc/docker/daemon.json << EOF
{
"registry-mirrors": ["https://b9pmyelo.mirror.aliyuncs.com"]
}
EOF
systemctl restart docker
else
echo 'docker 安装完毕';
fi
echo "############判断是否安装了wget##############"
if ! type wget >/dev/null 2>&1; then
echo 'wget 未安装';
echo '开始安装wget....';
yum -y install wget
else
echo 'wget 已安装';
fi
echo "############判断是否安装了dos2unix##############"
if ! type dos2unix >/dev/null 2>&1; then
echo 'dos2unix 未安装';
echo '开始安装dos2unix....';
yum -y install dos2unix*
else
echo 'dos2unix 已安装';
fi
echo "############判断是否安装了docker-compose##############"
if ! type docker-compose >/dev/null 2>&1; then
echo 'docker-compose 未安装';
echo '开始安装docker-compose....';
wget http://www.itxiaoshen.com:3001/assets/docker-compose
chmod +x docker-compose
mv docker-compose /usr/local/bin/
docker-compose -v
echo 'docker-compose安装完毕....';
else
echo 'docker-compose 已安装';
fi
echo '创建simple_ecommerce网络';
docker network create simple_ecommerce
# 添加执行权限
chmod +x ../bin/startup-all.sh
chmod +x ../bin/shutdown-all.sh
chmod +x ../bin/update.sh
chmod +x ../bin/wait-for-it.sh
# 修改编码
echo "修改编码...."
dos2unix startup-all.sh
dos2unix shutdown-all.sh
dos2unix update.sh
dos2unix wait-for-it.sh
sh startup-all.sh
wait-for-it.sh等待请求脚本
#!/usr/bin/env bash
# Use this script to test if a given TCP host/port are available
WAITFORIT_cmdname=${0##*/}
echoerr() { if [[ $WAITFORIT_QUIET -ne 1 ]]; then echo "$@" 1>&2; fi }
usage()
{
cat << USAGE >&2
Usage:
$WAITFORIT_cmdname host:port [-s] [-t timeout] [-- command args]
-h HOST | --host=HOST Host or IP under test
-p PORT | --port=PORT TCP port under test
Alternatively, you specify the host and port as host:port
-s | --strict Only execute subcommand if the test succeeds
-q | --quiet Don't output any status messages
-t TIMEOUT | --timeout=TIMEOUT
Timeout in seconds, zero for no timeout
-- COMMAND ARGS Execute command with args after the test finishes
USAGE
exit 1
}
wait_for()
{
if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then
echoerr "$WAITFORIT_cmdname: waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT"
else
echoerr "$WAITFORIT_cmdname: waiting for $WAITFORIT_HOST:$WAITFORIT_PORT without a timeout"
fi
WAITFORIT_start_ts=$(date +%s)
while :
do
if [[ $WAITFORIT_ISBUSY -eq 1 ]]; then
nc -z $WAITFORIT_HOST $WAITFORIT_PORT
WAITFORIT_result=$?
else
(echo -n > /dev/tcp/$WAITFORIT_HOST/$WAITFORIT_PORT) >/dev/null 2>&1
WAITFORIT_result=$?
fi
if [[ $WAITFORIT_result -eq 0 ]]; then
WAITFORIT_end_ts=$(date +%s)
echoerr "$WAITFORIT_cmdname: $WAITFORIT_HOST:$WAITFORIT_PORT is available after $((WAITFORIT_end_ts - WAITFORIT_start_ts)) seconds"
break
fi
sleep 1
done
return $WAITFORIT_result
}
wait_for_wrapper()
{
# In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692
if [[ $WAITFORIT_QUIET -eq 1 ]]; then
timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --quiet --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT &
else
timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT &
fi
WAITFORIT_PID=$!
trap "kill -INT -$WAITFORIT_PID" INT
wait $WAITFORIT_PID
WAITFORIT_RESULT=$?
if [[ $WAITFORIT_RESULT -ne 0 ]]; then
echoerr "$WAITFORIT_cmdname: timeout occurred after waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT"
fi
return $WAITFORIT_RESULT
}
# process arguments
while [[ $# -gt 0 ]]
do
case "$1" in
*:* )
WAITFORIT_hostport=(${1//:/ })
WAITFORIT_HOST=${WAITFORIT_hostport[0]}
WAITFORIT_PORT=${WAITFORIT_hostport[1]}
shift 1
;;
--child)
WAITFORIT_CHILD=1
shift 1
;;
-q | --quiet)
WAITFORIT_QUIET=1
shift 1
;;
-s | --strict)
WAITFORIT_STRICT=1
shift 1
;;
-h)
WAITFORIT_HOST="$2"
if [[ $WAITFORIT_HOST == "" ]]; then break; fi
shift 2
;;
--host=*)
WAITFORIT_HOST="${1#*=}"
shift 1
;;
-p)
WAITFORIT_PORT="$2"
if [[ $WAITFORIT_PORT == "" ]]; then break; fi
shift 2
;;
--port=*)
WAITFORIT_PORT="${1#*=}"
shift 1
;;
-t)
WAITFORIT_TIMEOUT="$2"
if [[ $WAITFORIT_TIMEOUT == "" ]]; then break; fi
shift 2
;;
--timeout=*)
WAITFORIT_TIMEOUT="${1#*=}"
shift 1
;;
--)
shift
WAITFORIT_CLI=("$@")
break
;;
--help)
usage
;;
*)
echoerr "Unknown argument: $1"
usage
;;
esac
done
if [[ "$WAITFORIT_HOST" == "" || "$WAITFORIT_PORT" == "" ]]; then
echoerr "Error: you need to provide a host and port to test."
usage
fi
WAITFORIT_TIMEOUT=${WAITFORIT_TIMEOUT:-15}
WAITFORIT_STRICT=${WAITFORIT_STRICT:-0}
WAITFORIT_CHILD=${WAITFORIT_CHILD:-0}
WAITFORIT_QUIET=${WAITFORIT_QUIET:-0}
# Check to see if timeout is from busybox?
WAITFORIT_TIMEOUT_PATH=$(type -p timeout)
WAITFORIT_TIMEOUT_PATH=$(realpath $WAITFORIT_TIMEOUT_PATH 2>/dev/null || readlink -f $WAITFORIT_TIMEOUT_PATH)
WAITFORIT_BUSYTIMEFLAG=""
if [[ $WAITFORIT_TIMEOUT_PATH =~ "busybox" ]]; then
WAITFORIT_ISBUSY=1
# Check if busybox timeout uses -t flag
# (recent Alpine versions don't support -t anymore)
if timeout &>/dev/stdout | grep -q -e '-t '; then
WAITFORIT_BUSYTIMEFLAG="-t"
fi
else
WAITFORIT_ISBUSY=0
fi
if [[ $WAITFORIT_CHILD -gt 0 ]]; then
wait_for
WAITFORIT_RESULT=$?
exit $WAITFORIT_RESULT
else
if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then
wait_for_wrapper
WAITFORIT_RESULT=$?
else
wait_for
WAITFORIT_RESULT=$?
fi
fi
if [[ $WAITFORIT_CLI != "" ]]; then
if [[ $WAITFORIT_RESULT -ne 0 && $WAITFORIT_STRICT -eq 1 ]]; then
echoerr "$WAITFORIT_cmdname: strict mode, refusing to execute subprocess"
exit $WAITFORIT_RESULT
fi
exec "${WAITFORIT_CLI[@]}"
else
exit $WAITFORIT_RESULT
fi
容器启动脚本startup-all.sh,其他只是示例流程,可以一步步完善补充
#!/usr/bin/env bash
echo '=====开始安装simple_ecommerce系统环境====='
#echo '=====开始运行mysql====='
#docker-compose -f ../yaml/mysql.yml up -d
#echo '=====开始运行nacos====='
#docker-compose -f ../yaml/nacos.yml up -d
#echo '=====nacos正在进行初始化,请等待...====='
#./wait-for-it.sh http://localhost:8848 --timeout=60 -- echo "=====nacos已经准备就绪====="
#echo '=====开始运行rocketmq====='
#docker-compose -f ../yaml/rocketmq.yml up -d
#echo '=====开始运行redis====='
#docker-compose -f ../yaml/redis.yml up -d
#echo '=====开始运行TinyID分布式系统全局ID服务====='
#docker-compose -f ../yaml/tinyid.yml up -d
#echo '=====开始运行ELK====='
#docker-compose -f ../yaml/elk.yml up -d
echo '======================'
echo '=====开始运行后台====='
echo '======================'
#echo '=====开始运行ecom-gateway====='
#docker-compose -f ../yaml/ecom-gateway.yml up -d
echo '=====开始运行ecom-storage-service====='
docker-compose -f ../yaml/ecom-storage-service.yml up -d
echo '=====开始运行ecom-order-service====='
docker-compose -f ../yaml/ecom-order-service.yml up -d
echo '执行完成 日志目录: ./log'
echo '======================'
echo '=====开始运行前台====='
echo '======================'
#echo '=====开始运行ecom_vue_web====='
#docker-compose -f ../yaml/ecom_vue_web.yml up -d
echo '======================================================'
echo '=====所有服务已经启动【请检查是否存在错误启动的】====='
echo '======================================================'
容器关闭脚本shutdown-all.sh
#!/usr/bin/env bash
echo '=====开始结束运行simple_ecommerce系统服务====='
#echo '=====结束运行mysql====='
#docker-compose -f ../yaml/mysql.yml down
#echo '=====结束运行nacos====='
#docker-compose -f ../yaml/nacos.yml down
#echo '=====结束运行rocketmq====='
#docker-compose -f ../yaml/rocketmq.yml down
#echo '=====结束运行redis====='
#docker-compose -f ../yaml/redis.yml down
#echo '=====结束运行TinyID分布式系统全局ID服务====='
#docker-compose -f ../yaml/tinyid.yml down
#echo '=====结束运行ELK====='
#docker-compose -f ../yaml/elk.yml down
echo '=========================='
echo '=====结束后台服务运行====='
echo '=========================='
#echo '=====结束运行ecom-gateway====='
#docker-compose -f ../yaml/ecom-gateway.yml down
echo '=====结束运行ecom-storage-service====='
docker-compose -f ../yaml/ecom-storage-service.yml down
echo '=====结束运行ecom-order-service====='
docker-compose -f ../yaml/ecom-order-service.yml down
echo '=========================='
echo '=====结束前台服务运行====='
echo '=========================='
#echo '=====结束运行ecom_vue_web====='
#docker-compose -f ../yaml/ecom_vue_web.yml down
echo '=============================='
echo '=====所有服务已经结束运行====='
echo '=============================='
更新镜像脚本update.sh,包含关闭容器、下载新的镜像、启动容器
#!/usr/bin/env bash
echo '=====开始更新simple_ecommerce系统镜像====='
echo '=====开始关闭运行的容器====='
sh shutdown-all.sh
#echo '=====开始更新ecom-gateway====='
#docker pull registry.itxs.cn/simple_ecommerce/ecom-gateway
echo '=====开始更新ecom-storage-service====='
docker pull registry.itxs.cn/simple_ecommerce/ecom-storage-service
echo '=====开始更新ecom-order-service====='
docker pull registry.itxs.cn/simple_ecommerce/ecom-order-service
#echo '=====开始更新cu_vue_web====='
#docker pull registry.itxs.cn/simple_ecommerce/ecom_vue_web
echo '=====删除docker标签为none的镜像====='
docker images | grep none | awk '{print $3}' | xargs docker rmi
echo '=====开始运行的一键部署脚本====='
sh startup-all.sh
# 进入到bin目录下,由于我这里本地有镜像,少了pull流程
sh ./init.sh
查看容器运行情况,容器正常运行
查看nacos服务的注册信息
访问订单接口http://192.168.50.95:4070/create/1001/1001/3 ,返回成功结果
查看订单表和库存表的数据都已更新,至此部署完毕
**本人博客网站 **IT小神 www.itxiaoshen.com
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK