程序配置的原則和實踐以及 Spring Boot 支持方式

原則

軟件須要在不一樣的環境中部署,代碼是保持不變的,可是不一樣的運行環境存在差別,因此須要使用配置適應不一樣的環境。好比:java

  • 數據庫,Redis,以及其餘 後端服務 的配置;
  • 第三方服務的證書,如 oAuth、支付接口 等;
  • 每份部署特有的配置,如域名等。

配置的原則是:代碼與配置要嚴格分離,不容許在代碼中使用常量保存配置。git

最多見的配置方式就是配置文件,按照配置文件的存儲位置,能夠分爲內部配置和外部配置:github

  • 內部配置:部署文件是發佈產物的一部分,存儲在發佈目錄中,甚至打包在一塊兒,好比 jar 包裏面的 properties 文件。這些配置文件在不一樣的環境間不存在差別,其實他們能夠看作是部署產物的一部分,好比 Spring 用來定義類建立和注入關係的 xml 文件。從運維的角度來看,儘管他們是配置文件,實際上和寫死代碼沒有什麼區別。反過來講,若是某個配置項在不一樣環境中是有差別的,就不該該放到內部;
  • 外部配置:不在部署產物內,須要在部署環境上修改。須要注意不要把這樣的文件提交到代碼控制系統,老是有人不當心這樣作。

配置漂移

構建好的程序被部署在服務器上後,爲了解決故障、性能優化、適應新的需求,須要對服務器和應用的配置進行更改。若是直接登陸服務器修改某個配置,隨着時間的推移和管理的複雜化,就會引起配置漂移。spring

這種能夠直接登陸修改的服務器稱爲可變服務器。可變服務器會形成開發、測試、生產服務器不一致,生產環境中不一樣的節點也不一致,容易出現運行問題。docker

要防止配置漂移,服務器要禁止手動修改,只能經過自動化部署形式更改配置,這種服務器就叫不可變服務器。不可變服務器消除了不一致性,開發、測試環境中獲得的程序包和最終到達服務器的程序包是徹底相同的。這樣就能防止配置漂移。shell

推薦方式

生產環境使用如下幾配置種技術:數據庫

  • 配置文件:使用外部配置,按照 Linux 的目錄規範在 /etc 目錄,或者其餘合適的位置;
  • 啓動參數:在啓動參數中注入配置數據,這是防止配置漂移的好辦法;
  • 環境變量:與啓動參數類似,也是推薦的方式;
  • 配置服務:使用某種集中配置平臺,好比 etcd、Zookeeper、Spring Cloud Config. 這些平臺使用不一樣的協議,在數據結構、存儲一致性方面有不一樣的設計思想,能夠選擇一個合適的。配置服務能夠支持動態修改,好比 Spring Cloud Config 提供了 refresh 端口,能夠調動這個端口在不重啓進程的狀況下修改配置項。

Spring Boot 配置方式

示例程序演示了 Spring Boot 配置方式,打包運行:後端

mvn package
export message=bonjour
java -Dmessage=hello \
    -jar spring-boot-config-sample-1.0.0-SNAPSHOT.jar \
    --message=hi \
    --spring.config.name=application,conf

message 配置出如今 4 個位置:性能優化

  • 系統環境變量 export message=bonjour
  • Java 屬性 -Dmessage=hello
  • 命令行參數 --message=hi
  • 內部配置文件 application.properties

啓動以後在 env 端口查看設置:服務器

$ curl http://localhost:8080/actuator/env
{
    "propertySources": [ { "name": "commandLineArgs", "properties": { "message": { "value": "hi" } } }, { "name": "systemProperties", "properties": { "message": { "value": "hello" } } }, { "name": "systemEnvironment", "properties": { "message": { "value": "bonjour", "origin": "System Environment Property \"message\"" } } }, { "name": "applicationConfig: [classpath:/application.properties]", "properties": { "message": { "value": "nihao", "origin": "class path resource [application.properties]:9:9" } } } ] }

這裏刪掉了一些無關的內容,能夠看到 message 設置是按照 commandLineArgssystemPropertiessystemEnvironmentapplicationConfig 的順序加載的,以最早出現的爲準。

spring.config.name 啓動參數定義了配置文件的名稱。Spring Boot 默認的配置文件是 application.properties,這裏添加了一個 conf.properties

Spring Boot 按照特定的順序加載配置項,位置和順序以下:

  1. DevTool 定義的配置項
  2. @TestPropertySource 標籤訂義的配置項
  3. @SpringBootTest#properties 標籤訂義的配置項
  4. 啓動參數
  5. SPRING_APPLICATION_JSON 環境變量
  6. ServletConfig 定義的 init 參數
  7. ServletContext 定義的 init 參數
  8. JNDI 屬性
  9. Java 系統屬性,使用 -Dkey=value 定義,System.getProperties() 能夠查看到
  10. 操做系統環境變量
  11. RandomValuePropertySource 定義的隨機值
  12. 帶 profile 的外部配置文件
  13. 帶 profile 的內部配置文件
  14. 不帶 profile 的外部配置文件
  15. 不帶 profile 的內部配置文件
  16. @Configuration 類型裏面的 @PropertySource 標籤訂義的配置
  17. SpringApplication.setDefaultProperties 方法設置的默認值

內外部配置文件的加載位置和順序以下:

  1. config 目錄
  2. . 當前目錄
  3. classpath:/config
  4. classpath:/

Docker

使用 Dockerfile 是在生產環境建立 Docker 鏡像的惟一推薦方式,示例程序提供了 Dockerfile 樣例。Dockerfile 將運行包和配置文件複製到鏡像裏:

RUN mkdir -p /opt/stack
COPY target/spring-boot-config-sample-1.0.0-SNAPSHOT.jar /opt/stack/
COPY ./conf.properties /opt/stack/

在環境變量和啓動參數中注入配置項:

ENV message=bonjour
ENTRYPOINT ["java", \ "-jar", \ "spring-boot-config-sample-1.0.0-SNAPSHOT.jar", \ "--spring.config.name=application,conf"]

定義了健康檢查規則:

HEALTHCHECK --interval=30s --timeout=10s \
    CMD curl -f http://localhost:8080/actuator/health || exit 1

Dockerfile 裏面還對鏡像系統進行了設置,提升了打開文件句柄數。Docker 是實現不可變服務器的最佳方式。

RUN ulimit -n 65536

使用 docker build 命令製做鏡像,第一次運行會下載一個 primetoninc/jdk 基礎鏡像,須要花一些時間:

docker build -t config-sample .

使用 docker run 命令運行程序:

docker run -it -p 8080:8080 config-sample

在實際環境上可使用 Kubernetes、Mesos 這樣的平臺管理和運行 Docker 鏡像,徹底能夠避免直接登陸服務器操做。

本文代碼示例:https://github.com/lane-cn/spring-boot-config-sample

相關文章
相關標籤/搜索