現在比較多的網際網路公司都在嘗試將微服務遷到雲上,這樣的能夠通過一些成熟的雲容器管理平臺更為方便地管理微服務叢集,從而提高微服務的穩定性,同時也能較好地提升團隊開發效率。
但是遷雲存在一定的技術難點,今天這篇文章主要介紹如何從0開始搭建一套基於K8s部署的SpringBoot案例教程。
基礎環境準備:
- mac作業系統
- SpringBoot的簡單Web工程
minikube的環境搭建
安裝一個適合我們初級入門的k8s環境,比較好的推薦是使用minikube工具,同時使用該工具可以更好地降低我們對k8s的學習門檻。首先我們需要下載minikube檔案:
curl -Lo minikube https://github.com/kubernetes/minikube/releases/download/v1.5.0/minikube-linux-amd64 && chmod +x minikube && sudo mv minikube /usr/local/bin/
在安裝minikube的時候,嘗試下載映象的時候可能會卡住,例如出現下邊的這類異常:
【idea @ Mac】>>>>>>minikube start --registry-mirror=https://w4i0ckag.mirror.aliyuncs.com
? Darwin 10.15.3 上的 minikube v1.16.0
✨ 根據現有的配置檔案使用 docker 驅動程式
? Starting control plane node minikube in cluster minikube
? Pulling base image ...
E0126 17:03:30.131026 34416 cache.go:180] Error downloading kic artifacts: failed to download kic base image or any fallback image
? Creating docker container (CPUs=2, Memory=1988MB) ...
? StartHost failed, but will try again: creating host: create: creating: setting up container node: preparing volume for minikube container: docker run --rm --entrypoint /usr/bin/test -v minikube:/var gcr.io/k8s-minikube/kicbase:v0.0.15-snapshot4@sha256:ef1f485b5a1cfa4c989bc05e153f0a8525968ec999e242efff871cbb31649c16 -d /var/lib: exit status 125
stdout:
stderr:
Unable to find image 'gcr.io/k8s-minikube/kicbase:v0.0.15-snapshot4@sha256:ef1f485b5a1cfa4c989bc05e153f0a8525968ec999e242efff871cbb31649c16' locally
docker: Error response from daemon: Get https://gcr.io/v2/: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers).
See 'docker run --help'.
? docker "minikube" container is missing, will recreate.
? Creating docker container (CPUs=2, Memory=1988MB) ...
? Failed to start docker container. Running "minikube delete" may fix it: recreate: creating host: create: creating: setting up container node: preparing volume for minikube container: docker run --rm --entrypoint /usr/bin/test -v minikube:/var gcr.io/k8s-minikube/kicbase:v0.0.15-snapshot4@sha256:ef1f485b5a1cfa4c989bc05e153f0a8525968ec999e242efff871cbb31649c16 -d /var/lib: exit status 125
stdout:
stderr:
Unable to find image 'gcr.io/k8s-minikube/kicbase:v0.0.15-snapshot4@sha256:ef1f485b5a1cfa4c989bc05e153f0a8525968ec999e242efff871cbb31649c16' locally
docker: Error response from daemon: Get https://gcr.io/v2/: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers).
See 'docker run --help'.
❌ Exiting due to GUEST_PROVISION: Failed to start host: recreate: creating host: create: creating: setting up container node: preparing volume for minikube container: docker run --rm --entrypoint /usr/bin/test -v minikube:/var gcr.io/k8s-minikube/kicbase:v0.0.15-snapshot4@sha256:ef1f485b5a1cfa4c989bc05e153f0a8525968ec999e242efff871cbb31649c16 -d /var/lib: exit status 125
stdout:
stderr:
Unable to find image 'gcr.io/k8s-minikube/kicbase:v0.0.15-snapshot4@sha256:ef1f485b5a1cfa4c989bc05e153f0a8525968ec999e242efff871cbb31649c16' locally
docker: Error response from daemon: Get https://gcr.io/v2/: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers).
See 'docker run --help'.
? If the above advice does not help, please let us know:
? https://github.com/kubernetes/minikube/issues/new/choose
此時可以嘗試先在宿主機上安裝好對應的映象檔案:
docker pull anjone/kicbase
然後minikube在啟動的時候使用本地的映象,這樣可以減少minikube start過程的耗時。minikube下載了之後便到了啟動環節:
minikube start --vm-driver=docker --base-image="anjone/kicbase"
如果啟動失敗,不妨試試更換指定的映象倉庫,例如下邊這段:
minikube start
--registry-mirror=https://bmtb46e4.mirror.aliyuncs.com
--vm-driver=docker
--base-image="anjone/kicbase"
--image-repository=registry.cn-hangzhou.aliyuncs.com/google_containers
這裡頭我大概介紹一下啟動引數的含義:
--registry-mirror
這裡的地址會和啟動的minikube內部的docker.daemon檔案中所指向的映象倉庫地址一致。--vm-driver
虛擬機器引擎 這裡是指minikube的內部通過docker來作為核心--base-image
宣告好基礎映象,如果宿主機內部有對應映象,就不需要額外拉取--image-repository
拉取映象的倉庫
當minikube啟動成功之後,大致如下所示:
【idea @ Mac】>>>>>>minikube start --vm-driver=docker --base-image="anjone/kicbase"
? Darwin 10.15.3 上的 minikube v1.16.0
✨ 根據現有的配置檔案使用 docker 驅動程式
? Starting control plane node minikube in cluster minikube
? docker "minikube" container is missing, will recreate.
? Creating docker container (CPUs=2, Memory=1988MB) ...
❗ This container is having trouble accessing https://k8s.gcr.io
? To pull new external images, you may need to configure a proxy: https://minikube.sigs.k8s.io/docs/reference/networking/proxy/
? 正在 Docker 19.03.2 中準備 Kubernetes v1.20.0…
▪ Generating certificates and keys ...
▪ Booting up control plane ...\
▪ Configuring RBAC rules ...
? Verifying Kubernetes components...
? Enabled addons: default-storageclass
? Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default
【idea @ Mac】>>>>>>
好了,接下來便到了部署SpringBoot應用的部分了。
基於SpringBoot部署到k8s中
首先我們需要搭建一個簡單的SpringBoot應用:
引入dependency依賴
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
打包docker映象的配置:
<build>
<finalName>打包出來的映象名稱</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.2.5.RELEASE</version>
</plugin>
<!-- Docker maven plugin -->
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>1.0.0</version>
<configuration>
<imageName>${project.artifactId}</imageName>
<imageTags>
<tag>1.0.1</tag>
</imageTags>
<dockerDirectory>src/main/docker</dockerDirectory>
<resources>
<resource>
<targetPath>/</targetPath>
<directory>${project.build.directory}</directory>
<include>${project.build.finalName}.jar</include>
</resource>
</resources>
</configuration>
</plugin>
<!-- Docker maven plugin -->
</plugins>
</build>
接著是簡單的controller和啟動類:
@RestController
@RequestMapping(value = "/test")
public class TestController {
@GetMapping(value = "/do-test")
public String doTest(){
System.out.println("this is a test");
return "success";
}
}
@SpringBootApplication
public class WebApplication {
public static void main(String[] args) {
SpringApplication.run(WebApplication.class);
}
}
編寫Dockerfile的指令碼:
FROM openjdk:8-jdk-alpine
VOLUME /tmp
#將springboot-k8s-template.jar複製到容器內部 並且別名叫springboot-k8s-template-v1.jar
ADD springboot-k8s-template.jar springboot-k8s-template-v1.jar
#相當於在容器中用cmd命令執行jar包 指定外部配置檔案
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/springboot-k8s-template-v1.jar"]
然後進入到Dockerfile的目錄底下,進行映象的構建:
【idea @ Mac】>>>>>>docker build -t springboot-k8s-template:1.0 .
[+] Building 0.5s (7/7) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 419B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/openjdk:8-jdk-alpine 0.0s
=> [internal] load build context 0.3s
=> => transferring context: 17.60MB 0.3s
=> CACHED [1/2] FROM docker.io/library/openjdk:8-jdk-alpine 0.0s
=> [2/2] ADD springboot-k8s-template.jar springboot-k8s-template-v1.jar 0.1s
=> exporting to image 0.1s
=> => exporting layers 0.1s
=> => writing image sha256:86d02961c4fa5bb576c91e3ebf031a3d8b140ddbb451b9613a2c4d601ac4d853 0.0s
=> => naming to docker.io/library/springboot-k8s-template:1.0 0.0s
Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them
【idea @ Mac】>>>>>>docker images | grep template
springboot-k8s-template 1.0 86d02961c4fa 48 seconds ago 122MB
構建完成之後,將本地映象打包釋出到映象倉庫中,這裡我是通過推送到阿里雲映象倉庫的方式來處理的。
推送本地映象到阿里雲
首先是登入到docker倉庫,然後記錄對應的tag資訊,最終推送映象。
$ docker login --username=[阿里雲賬戶名稱] registry.cn-qingdao.aliyuncs.com
$ docker tag [ImageId] registry.cn-qingdao.aliyuncs.com/idea_hub/idea_resp:[映象版本號]
$ docker push registry.cn-qingdao.aliyuncs.com/idea_hub/idea_resp:[映象版本號]
例如:
【idea @ Mac】>>>>>>docker images | grep config
qiyu-framework-k8s-config 1.0 6168639757e9 2 minutes ago 122MB
【idea @ Mac】>>>>>>docker tag 6168639757e9 registry.cn-qingdao.aliyuncs.com/idea_hub/idea_resp:qiyu-framework-k8s-config-1.0
【idea @ Mac】>>>>>>docker push registry.cn-qingdao.aliyuncs.com/idea_hub/idea_resp:qiyu-framework-k8s-config-1.0
The push refers to repository [registry.cn-qingdao.aliyuncs.com/idea_hub/idea_resp]
1ace00556b41: Pushed
ceaf9e1ebef5: Layer already exists
9b9b7f3d56a0: Layer already exists
f1b5933fe4b5: Layer already exists
qiyu-framework-k8s-config-1.0: digest: sha256:50c1a87484f6cbec699d65321fa5bbe70f5ad6da5a237e95ea87c7953a1c80da size: 1159
【idea @ Mac】>>>>>>
請根據實際映象資訊替換示例中的[ImageId]和[映象版本號]引數。
將映象檔案打包並且推送到映象倉庫之後,可以通過在yaml檔案中編寫對應的映象地址,這樣就能保證在映象下載的時候能從倉庫拉取出對應的映象檔案。
通常專案中我們會採用統一的yaml檔案來進行pod節點的部署與構建。
yaml配置檔案:
apiVersion: apps/v1 #kubectl api-versions 可以通過這條指令去看版本資訊
kind: Deployment # 指定資源類別
metadata: #資源的一些後設資料
name: springboot-k8s-template-deployment #deloyment的名稱
labels:
app: springboot-k8s-template-deployment #標籤
spec:
replicas: 2 #建立pod的個數
selector:
matchLabels:
app: springboot-k8s-template-deployment #滿足標籤為這個的時候相關的pod才能被排程到
template:
metadata:
labels:
app: springboot-k8s-template-v1
spec:
containers:
- name: springboot-k8s-template-v1
image: registry.cn-qingdao.aliyuncs.com/idea_hub/idea_resp:1.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
由於阿里雲的映象倉庫需要使用者賬號密碼許可權訪問,所以這裡我們可以嘗試簡單一些的策略,登入minikube的內部,提前下載好對應的阿里雲映象。
通過 minikube ssh 指令即可登入到minikube的內部:
採用docker pull指令即可下載對應資源:
docker@minikube:~$ docker pull registry.cn-qingdao.aliyuncs.com/idea_hub/idea_resp:springboot-k8s-template-1.0
springboot-k8s-template-1.0: Pulling from idea_hub/idea_resp
e7c96db7181b: Already exists
f910a506b6cb: Already exists
c2274a1a0e27: Already exists
d2fe98fe1e4e: Pull complete
Digest: sha256:dc1c9caa101df74159c1224ec4d7dcb01932aa8f4a117bba603ffcf35e91c60c
Status: Downloaded newer image for registry.cn-qingdao.aliyuncs.com/idea_hub/idea_resp:springboot-k8s-template-1.0
registry.cn-qingdao.aliyuncs.com/idea_hub/idea_resp:springboot-k8s-template-1.0
docker@minikube:~$
檢視對應的映象檔案
映象拉取策略可以對照官網的介紹來系統認識:
在yaml檔案裡我選用了IfNotPresent策略,這條策略能夠保證當本地有映象的時候優先選用本地,沒有才選擇網路拉取。
最後是找到相關的yaml檔案進行pod的部署啟動。
kubectl create -f ./k8s-springboot-template.yaml
此時通過 kubectl get pod 命令可以看到對應的pod節點:
最終需要暴露deployment服務:
【idea @ 拍了拍我的iterm2 說】>>>>>> kubectl expose deployment springboot-k8s-template-deployment --type=NodePort
service/springboot-k8s-template-deployment exposed
【idea @ 拍了拍我的iterm2 說】>>>>>> kubectl get pods
NAME READY STATUS RESTARTS AGE
springboot-k8s-template-deployment-687f8bf86d-gqxcp 1/1 Running 0 7m50s
springboot-k8s-template-deployment-687f8bf86d-lcq5p 1/1 Running 0 7m50s
【idea @ 拍了拍我的iterm2 說】>>>>>> minikube service springboot-k8s-template-deployment
|-----------|------------------------------------|-------------|---------------------------|
| NAMESPACE | NAME | TARGET PORT | URL |
|-----------|------------------------------------|-------------|---------------------------|
| default | springboot-k8s-template-deployment | 8080 | http://192.168.49.2:31179 |
|-----------|------------------------------------|-------------|---------------------------|
? Starting tunnel for service springboot-k8s-template-deployment.
|-----------|------------------------------------|-------------|------------------------|
| NAMESPACE | NAME | TARGET PORT | URL |
|-----------|------------------------------------|-------------|------------------------|
| default | springboot-k8s-template-deployment | | http://127.0.0.1:57109 |
|-----------|------------------------------------|-------------|------------------------|
? 正通過預設瀏覽器開啟服務 default/springboot-k8s-template-deployment...
❗ Because you are using a Docker driver on darwin, the terminal needs to be open to run it.
暴露之後訪問:
http://127.0.0.1:57109/test/do-test
驗證介面正常。
minikube日誌檢視:
kubectl logs -f springboot-k8s-template-deployment-687f8bf86d-lcq5p