微服務不同環境到底該如何部署?最佳實踐是什麼?

ITPUB社群發表於2023-04-26

來源:WU雙


你們是怎麼部署微服務的?

如何處理不同的環境部署的?

今天給大家帶來我們的一些實踐。


1

微服務部署的挑戰

一句話來說,微服務部署的最大挑戰是如何保證不同的環境部署程式碼的一致性,以及如何區分不同的部署環境。

作為開發,可能我們大多數時間都在開發程式碼,卻忽略了釋出的重要性,實際釋出才是到使用者手裡的最後一步,這一步做的不好,那麼你的軟體價值則不能很好交付到使用者手裡,作為開發,你自己的體驗也不好。

Docker正式因為改變了部署交付的方式,才引起了革命,產生了如此廣泛的影響。

所以我們需要重視並做好交付這一步。


2

微服務部署的方式

微服務的部署方式有多種,傳統的比如打個Jar包,透過 java -jar 來啟動,在雲端計算時代,更多的則是透過構建Docker映象的方式,透過docker run 來啟動。

這裡的一個主要問題是,如何在不同的環境中去部署相應的服務。

對於一般公司來講,我們會有開發、沙箱、預生產、生產環境,不同的環境,會有不同的配置,當然微服務背景下,我們都會引入配置中心,但不同環境下,還是需要不同的配置中心配置。

那麼如何在不同的環境下去部署?

讓我們來看看幾種解決方案。(說明:以下都是透過構建Docker映象的方式來部署的方案。)

方案一:不同的環境打不同的映象

此種方案透過配合maven profile,maven-antrun-plugin外掛,在不同的環境下,將不同環境的配置檔案覆蓋resources目錄下的配置最後在打成Jar包,然後透過docker-maven-plugin外掛,將應用Jar包構建成Docker映象,推送到不同環境的Docker映象倉庫。

不同環境的部署,只需要到不同環境的Docker映象倉庫中拉取映象,然後啟動就行了。

關鍵步驟資訊如下:

1)pom.xml中提前設定好不同的profile,不同的profile將使用不同的配置檔案進行打包並構建映象。




































































         <!-- 這裡以沙箱環境的映象打包為例 -->         <profile>            <id>sand</id>            <build>                <plugins>                    <plugin>                        <groupId>org.apache.maven.plugins</groupId>                        <artifactId>maven-antrun-plugin</artifactId>                        <version>1.8</version>                        <executions>                            <execution>                                <phase>validate</phase>                                <configuration>                                    <target>                                        <move file="./config/sand/bootstrap.yml"                                              tofile="./src/main/resources/bootstrap.yml"                                              overwrite="true"/>                                        <echo>${revision}</echo>                                        <replace file="src/main/resources/bootstrap.yml" token="@version@"                                                 value="${revision}"/>                                    </target>                                </configuration>                                <goals>                                    <goal>run</goal>                                </goals>                            </execution>                        </executions>                    </plugin>                    <plugin>                        <groupId>com.spotify</groupId>                        <artifactId>docker-maven-plugin</artifactId>                        <version>1.0.0</version>                        <executions>                            <execution>                                <id>build-image</id>                                <phase>package</phase>                                <goals>                                    <goal>build</goal>                                    <goal>push</goal>                                </goals>                            </execution>                        </executions>                        <configuration>                            <!-- 映象名稱 -->                            <imageName>127.0.0.1:5000/${project.artifactId}</imageName>                            <!-- 指定標籤 -->                            <imageTags>                                <imageTag>${revision}</imageTag>                            </imageTags>                            <dockerHost>{project.basedir}/src/main/assembly</dockerDirectory>                            <buildArgs>                                <APP_NAME>${project.build.finalName}</APP_NAME>                            </buildArgs>                            <resources>                                <resource>                                    <directory>${project.build.directory}</directory>                                    <includes>                                        <include>${project.build.finalName}.jar</include>                                    </includes>                                </resource>                            </resources>                        </configuration>                    </plugin>                </plugins>            </build>        </profile>

2)maven打包階段指定不同的profile


mvn clean deploy -P sand

上述部署方案整體流程如下圖所示:

微服務不同環境到底該如何部署?最佳實踐是什麼?

上述方案的問題是,需要提前將所有的配置檔案都放在程式碼倉庫中,在環境多的時候不便於維護,特別是在多資料中心的情況下。另外不同的環境實際部署的是不同的映象,不符合Docker的一次構建,處處部署的思想,當然還需要不同的環境部署不同的映象倉庫,也有一定的資源浪費。

方案二:將所有環境打進一個映象,透過spring.profiles.active來生效不同的環境

此種方案是將所有環境都打包到一個映象中,然後在啟動的時候透過Spring的 spring.profiles.active 來生效不同的環境配置,關鍵步驟如下:

1)將所有環境的配置放到一個配置檔案中,或者是放在不同環境的配置檔案中(下面是將所有的配置都放到/src/main/resources/bootstrap.yml檔案中):




























































server:  port: 8888spring:  application:    name: my-app  profiles:    # 預設啟用dev環境    active: dev   
# 開發環境---spring:  config:    activate:      on-profile: dev  cloud:    nacos:      discovery:        server-addr:         metadata:          version: '1.0.0-SNAPSHOT'      config:        server-addr: ${spring.cloud.nacos.discovery.server-addr}        file-extension: yaml        name: ${spring.application.name}
# 沙箱環境---spring:  config:    activate:      on-profile: sand  cloud:    nacos:      discovery:        server-addr:         metadata:          version: '1.0.0-SNAPSHOT'      config:        server-addr: ${spring.cloud.nacos.discovery.server-addr}        file-extension: yaml        name: ${spring.application.name}
# 生產環境---spring:  config:    activate:      on-profile: prod  cloud:    nacos:      discovery:        server-addr:         metadata:          version: '1.0.0-SNAPSHOT'      config:        server-addr: ${spring.cloud.nacos.discovery.server-addr}        file-extension: yaml        name: ${spring.application.name}

2)啟動的時候,透過啟動指令碼指定不同的active:


JAVA_OPTS="$JAVA_OPTS -Dspring.profiles.active=sand"

上述部署方案整體流程如下圖所示:

微服務不同環境到底該如何部署?最佳實踐是什麼?

上述方案可以確保不同環境的映象一致性,符合Docker的構建一次,處處部署的思想,當然問題是需要提前將所有環境都放在專案裡,這會導致在環境變化時需要修改程式碼的問題(程式碼和配置沒有完全分離),也會有安全問題,因為你的生產環境地址也暴露無遺。

方案三:將所有環境抽離出環境變數,在應用啟動的時候透過環境變數注入

此種方案利用了Spring透過命令列來指定相關配置的特性,真正實現了程式碼與配置的完全分離。程式碼庫裡不存放任何的環境地址(可以只存放本地開發環境地址),所有的環境地址都透過環境變數的方式注入進去。這樣可以真正做到,一套程式碼,處處執行,即使在新增資料中心,需要重新部署的時候,也不需要修改任何程式碼,直接透過環境變數指定即可。

關鍵步驟如下:

1)Docker部署指令碼在啟動容器時將環境變數注入:


docker run -e SPRING_CLOUD_NACOS_DISCOVERY_SERVER_ADDR="localhost:8840" -d --network=host -v /log/:/log/ ${SERVER_DOCKER}/${SERVICE_NAME}:latest

2)應用啟動指令碼透過環境變數,獲取相應的地址:






# 指定nacos地址JAVA_OPTS="$JAVA_OPTS -Dspring.cloud.nacos.discovery.server-addr=${SPRING_CLOUD_NACOS_DISCOVERY_SERVER_ADDR}"# 指定日誌檔案JAVA_OPTS="$JAVA_OPTS -DLOGBACK_LOG_HOME=${LOGBACK_LOG_HOME}"JAVA_OPTS="$JAVA_OPTS -jar ${DEPLOY_DIR}/${SERVER_NAME}.jar"

上述部署方案整體流程如下圖所示:

微服務不同環境到底該如何部署?最佳實踐是什麼?

上述方案實現了程式碼與配置的真正分離,程式碼庫裡無需存放任何地址(可以指保留開發環境地址),不同的部署環境只要注入不同的環境配置即可。可以稱得上是最佳實踐。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70024420/viewspace-2948939/,如需轉載,請註明出處,否則將追究法律責任。

相關文章