概述
我們使用前面《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 "107734588@qq.com"
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 "107734588@qq.com"
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