基於docker的微服務容器化與編排
準備
在本人的微服務系列中,已經演示了各個spring cloud微服務元件的使用,以及相關的示例微服務應用。在每次啟動微服務和對微服務進行擴容、縮容都不方便,本文使用docker-compose將以下的微服務容器化,並進行自動化部署。
相關程式碼請參考:springcloud-demo
各服務治理元件的介紹,請參考我的微服務系列文章。
1.微服務治理元件列表
名稱 | 描述 | 內部埠 | 暴露埠 | 是否部署叢集 |
---|---|---|---|---|
discovery | 基於Eureka Server的服務註冊中心 | 8761/8762 | 8761/8762 | 是 |
configserver | 基於cloud config的配置中心 | 8089 | 8089 | 是 |
gateway | 基於zuul的API閘道器 | 8086 | 8086 | 否 |
track | 基於seluth+zipkin的服務跟蹤 | 9411 | 9411 | 否 |
hystrix-dashboard | 基於hystrix-dashboard的服務監控 | 8087 | 8087 | 否 |
hystrix-turbine-mq | 基於turbine+rabbitmq的服務監控資料收集 | 8089 | 8089 | 否 |
2.微服務示例列表
名稱 | 描述 | 內部埠 | 暴露埠 | 是否部署叢集 |
---|---|---|---|---|
hello | 服務提供者,依賴mysql資料庫 | 8000 | 自動 | 是 |
world | 服務提供者 | 8010 | 自動 | 是 |
helloworld | 服務消費者,使用restTemplate+ribbon呼叫 | 8020 | 自動 | 是 |
helloworld-feign | 服務消費者,使用feign方式呼叫 | 8030 | 自動 | 是 |
3.環境與工具
- 環境 linux (ubuntu 16)
- 工具 docker
+gitlab
+rabbitmq
+docker registry
+intellij idea
maven
操作步驟
本文編寫兩個docker-compose.yml檔案,將服務治理和服務示例分開,主要是因為服務示例依賴了服務治理,部分示例必須要等待服務治理元件載入完畢才能正常啟動,比如hello
專案使用了配置中心config server
的配置,config server
未載入完畢,hello
專案啟動異常。
雖然depends_on
、links
等具有啟動順序的問題,但解決不了啟動是否 ready
的問題,關於這個問題,可以參考我的文章:docker-compose 啟動順序
1. 編寫 Dockerfile
在每個專案的根目錄中,編寫Dockerfile,檔案內容為
FROM java:8-jre-alpine
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/' /etc/apk/repositories
VOLUME /tmp
ADD target/*.jar app.jar
RUN sh -c 'touch /app.jar'
RUN echo $(date) > /image_built_at
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar","--spring.profiles.active=${SPRING_PROFILES_ACTIVE}"]
其中SPRING_PROFILES_ACTIVE
為後面docker-compose.yml傳入的環境變數,指定專案以使用哪段配置啟動。
2. 在原有的配置檔案application.yml增加spring.profiles:docker
的配置
主要是使用docker後,服務依賴的其他服務的連線發生改變,通過配置環境變數來動態接收docker-compose的配置引數。
- track增加的spring.profiles:docker
配置
---
spring:
profiles: docker
server:
port: ${{SERVER_PORT}:9411}
eureka:
client:
serviceUrl:
defaultZone: ${EUREKA_SERVER_LIST}
- hello 增加的
spring.profiles:docker
配置
---
spring:
profiles: docker
datasource:
url: jdbc:mysql://mysql:3306/${{MYSQL_DATABASE}:hello}
username: ${{MYSQL_USERNAME}:user}
password: ${{MYSQL_PASSWORD}:passworld}
testWhileIdle: true
validationQuery: SELECT 1
jpa:
show-sql: false
hibernate:
ddl-auto: update
naming-strategy: org.hibernate.cfg.ImprovedNamingStrategy
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL5Dialect
zipkin:
base-url: http://track:9411
eureka:
client:
serviceUrl:
defaultZone: ${EUREKA_SERVER_LIST}
${{MYSQL_USERNAME}:user} 是指配置檔案在啟動的時候如果沒有讀取到環境變數MYSQL_USERNAME的值,則使用預設值user。這種配置在開發的時候十分有用,比如切換開發、測試、生產環境配置。
3. 編寫批量編譯的shell指令碼images-build.sh
該指令碼將進入到各個專案中,使用maven對專案進行打包,然後使用docker,根據Dockerfile對專案進行構建,生成分別帶有:lastest 和當前日期標籤的兩個映象。
#!/bin/bash
# 編譯所有的程式碼,生成docker 映象
function progress(){
local GREEN CLEAN
GREEN='\033[0;32m'
CLEAN='\033[0m'
printf "\n${GREEN}[email protected] ${CLEAN}\n" >&2
}
set -e
# 映象倉庫字首
REGPREFIX=127.0.0.1:5000/billjiang
TOTAL=10
#discovery server
progress "Building discovery-server(1/${TOTAL}) jar file ..."
cd common/discovery
mvn clean package -DskipTests
progress "Building discovery(eureka server)(1/${TOTAL}) docker image ..."
docker tag $(docker build -t ${REGPREFIX}/discovery -q .) ${REGPREFIX}/discovery:$(date -u "+%Y%m%d-%H%M%S")
cd -
#config server
progress "Building config-server(2/${TOTAL}) jar file ..."
cd common/configserver
mvn clean package -DskipTests
progress "Building config server(2/${TOTAL}) docker image ..."
docker tag $(docker build -t ${REGPREFIX}/configserver -q .) ${REGPREFIX}/configserver:$(date -u "+%Y%m%d-%H%M%S")
cd -
#gateway
progress "Building gateway-zuul(3/${TOTAL}) jar file ..."
cd common/gateway
mvn clean package -DskipTests
progress "Building gateway-zuul(3/${TOTAL}) docker image ..."
docker tag $(docker build -t ${REGPREFIX}/gateway -q .) ${REGPREFIX}/gateway:$(date -u "+%Y%m%d-%H%M%S")
cd -
#track sleuth+zipkin
progress "Building track(sleuth+zipkin)(4/${TOTAL}) jar file ..."
cd common/track
mvn clean package -DskipTests
progress "Building track by sleuth+zipkin(4/${TOTAL}) docker image ..."
docker tag $(docker build -t ${REGPREFIX}/track -q .) ${REGPREFIX}/track:$(date -u "+%Y%m%d-%H%M%S")
cd -
#hystrix-dashboard
progress "Building hystrix-dashboard(5/${TOTAL}) jar file ..."
cd common/hystrix-dashboard
mvn clean package -DskipTests
progress "Building hystrix-dashboard(5/${TOTAL}) docker image ..."
docker tag $(docker build -t ${REGPREFIX}/hystrix-dashboard -q .) ${REGPREFIX}/hystrix-dashboard:$(date -u "+%Y%m%d-%H%M%S")
cd -
#hystrix-turbine-mq
progress "Buildinhg hystrix-turbine-mq(6/${TOTAL}) jar file ..."
cd common/hystrix-turbine-mq
mvn clean package -DskipTests
progress "Building hystrix-turbine-mq(6/${TOTAL}) docker image ..."
docker tag $(docker build -t ${REGPREFIX}/hystrix-turbine-mq -q .) ${REGPREFIX}/hystrix-turbine-mq:$(date -u "+%Y%m%d-%H%M%S")
cd -
#hello
progress "Buildinhg hello service(7/${TOTAL}) jar file ..."
cd service/hello
mvn clean package -DskipTests
progress "Building hello service(7/${TOTAL}) docker image ..."
docker tag $(docker build -t ${REGPREFIX}/hello -q .) ${REGPREFIX}/hello:$(date -u "+%Y%m%d-%H%M%S")
cd -
#world
progress "Buildinhg world service(8/${TOTAL}) jar file ..."
cd service/world
mvn clean package -DskipTests
progress "Building world service(8/${TOTAL}) docker image ..."
docker tag $(docker build -t ${REGPREFIX}/world -q .) ${REGPREFIX}/world:$(date -u "+%Y%m%d-%H%M%S")
cd -
#helloworld
progress "Buildinhg helloworld service(9/${TOTAL}) jar file ..."
cd service/helloworld
mvn clean package -DskipTests
progress "Building helloworld service(9/${TOTAL}) docker image ..."
docker tag $(docker build -t ${REGPREFIX}/helloworld -q .) ${REGPREFIX}/helloworld:$(date -u "+%Y%m%d-%H%M%S")
cd -
#helloworld-feign
progress "Buildinhg helloworld-feign service(10/${TOTAL}) jar file ..."
cd service/helloworld-feign
mvn clean package -DskipTests
progress "Building helloworld-feign service(10/${TOTAL}) docker image ..."
docker tag $(docker build -t ${REGPREFIX}/helloworld-feign -q .) ${REGPREFIX}/helloworld-feign:$(date -u "+%Y%m%d-%H%M%S")
cd -
4. 進入到專案目錄springcloud-demo
,執行bash images-build.sh
進行批量編譯打包
5. 建立服務治理元件的docker-compose.yml
,編寫如下內容
version: "2"
services:
#啟動註冊中心eureka-server叢集 集中管理/服務註冊/服務發現
discovery1:
container_name: discovery1
image: 127.0.0.1:5000/billjiang/discovery
ports:
- "8761:8761"
environment:
- ADDITIONAL_EUREKA_SERVER_LIST=http://discovery2:8762/eureka/
- SPRING_PROFILES_ACTIVE=docker
- SERVER_PORT=8761
discovery2:
container_name: discovery2
image: 127.0.0.1:5000/billjiang/discovery
ports:
- "8762:8762"
environment:
- ADDITIONAL_EUREKA_SERVER_LIST=http://discovery1:8761/eureka/
- SPRING_PROFILES_ACTIVE=docker
- SERVER_PORT=8762
links:
- discovery1
#啟動配置中心config-server叢集 配置更新/配置集中管理/多環境配置
config1:
container_name: configserver1
image: 127.0.0.1:5000/billjiang/configserver
ports:
- "8090:8090"
environment:
- EUREKA_SERVER_LIST=http://discovery1:8761/eureka/,http://discovery2:8762/eureka/
- SPRING_PROFILES_ACTIVE=docker
- SERVER_PORT=8090
links:
- discovery1
- discovery2
config2:
container_name: configserver2
image: 127.0.0.1:5000/billjiang/configserver
ports:
- "8091:8091"
environment:
- EUREKA_SERVER_LIST=http://discovery1:8761/eureka/,http://discovery2:8762/eureka/
- SPRING_PROFILES_ACTIVE=docker
- SERVER_PORT=8091
links:
- discovery1
- discovery2
#啟動閘道器gateway,可配置成叢集,使用nginx進行負載 智慧路由/安全控制/負載均衡
gateway:
container_name: gateway
image: 127.0.0.1:5000/billjiang/gateway
ports:
- "8086:8086"
environment:
- EUREKA_SERVER_LIST=http://discovery1:8761/eureka/,http://discovery2:8762/eureka/
- SPRING_PROFILES_ACTIVE=docker
- SERVER_PORT=8086
links:
- discovery1
- discovery2
# 啟動seluth+zipkin zipkin服務跟蹤/依賴視覺化
track:
container_name: track
image: 127.0.0.1:5000/billjiang/track
ports:
- "9411:9411"
environment:
- EUREKA_SERVER_LIST=http://discovery1:8761/eureka/,http://discovery2:8762/eureka/
- SPRING_PROFILES_ACTIVE=docker
- SERVER_PORT=9411
links:
- discovery1
- discovery2
# hystrix
# 啟動hystrix-dashboard
hystrix-dashboard:
container_name: hystrix-dashboard
image: 127.0.0.1:5000/billjiang/hystrix-dashboard
ports:
- "8087:8087"
environment:
- EUREKA_SERVER_LIST=http://discovery1:8761/eureka/,http://discovery2:8762/eureka/
- SPRING_PROFILES_ACTIVE=docker
- SERVER_PORT=8087
links:
- discovery1
- discovery2
# 啟動hystrix-turbine-mq 基於訊息中介軟體的實時效能資料收集
hystrix-turbine-mq:
container_name: hystrix-turbine-mq
image: 127.0.0.1:5000/billjiang/hystrix-turbine-mq
ports:
- "8089:8089"
environment:
- EUREKA_SERVER_LIST=http://discovery1:8761/eureka/,http://discovery2:8762/eureka/
- SPRING_PROFILES_ACTIVE=docker
- SERVER_PORT=8089
links:
- discovery1
- discovery2
mysql:
container_name: mysql
image: mysql:5.7
environment:
- MYSQL_ROOT_PASSWORD=passw0rd
- MYSQL_DATABASE=foodb
- MYSQL_USER=user1
- MYSQL_PASSWORD=passw0rd
6. 在service目錄下,建立服務示例的docker-compose.yml
,編寫如下內容
version: "2"
services:
# 啟動 hello
hello:
image: 127.0.0.1:5000/billjiang/hello
ports:
- "8000"
environment:
- EUREKA_SERVER_LIST=http://discovery1:8761/eureka/,http://discovery2:8762/eureka/
- SPRING_PROFILES_ACTIVE=docker
- MYSQL_DATABASE=foodb
- MYSQL_USERNAME=user1
- MYSQL_PASSWORD=passw0rd
external_links:
- mysql
- config1
- config2
- gateway
- track
# 啟動 world
world:
image: 127.0.0.1:5000/billjiang/world
ports:
- "8010"
environment:
- EUREKA_SERVER_LIST=http://discovery1:8761/eureka/,http://discovery2:8762/eureka/
- SPRING_PROFILES_ACTIVE=docker
- SERVER_PORT:8010
external_links:
- config1
- config2
- gateway
- track
# 啟動 helloworld
helloworld:
image: 127.0.0.1:5000/billjiang/helloworld
ports:
- "8020"
environment:
- EUREKA_SERVER_LIST=http://discovery1:8761/eureka/,http://discovery2:8762/eureka/
- SPRING_PROFILES_ACTIVE=docker
- SERVER_PORT:8020
external_links:
- config1
- config2
- gateway
- track
links:
- hello
- world
# 啟動 hello
helloworld-feign:
image: 127.0.0.1:5000/billjiang/helloworld-feign
ports:
- "8030"
environment:
- EUREKA_SERVER_LIST=http://discovery1:8761/eureka/,http://discovery2:8762/eureka/
- SPRING_PROFILES_ACTIVE=docker
- SERVER_PORT=8030
external_links:
- config1
- config2
- gateway
- track
links:
- hello
- world
# 其他服務 ..........................
networks:
default:
external:
name: springclouddemo_default
因為docker-compose啟動的時候預設會建立一個springclouddemo_default
的網路,兩個網路要通訊,所以服務示例指定使用springclouddemo_default
,這樣元件之間客戶互相通訊了。
6. 啟動服務治理的docker-compose.yml
在springcloud-demo
根目錄下,使用docker-compose up
啟動服務編排,如下介面所示:
啟動後,開啟註冊中心地址,檢視已經啟動的服務:
7. 連線外部docker容器
配置中心使用到了gitlab, 服務跟蹤track使用了rabbitmq,這兩個容器都不在docker-compose之中,要使得能夠互相連通,要把這兩個容器也加入到springclouddemo_default
網路。
docker network connect springclouddemo_default gitlab
docker network connect springclouddemo_default rabbitmq
使用docker network inspect springclouddemo_default
可以檢視到已經加入網路的容器。
8. 啟動服務示例編排docker-compose.yml
進入到service
目錄,使用docker-compose up
啟動服務示例編排,如下所示:
9. 在Eureka Server檢視新增的服務
10. 可以使用如下命令對服務進行擴容
重新整理Eureka Server,可以看到服務已經擴充套件到三個節點。