學習了K8S的基礎知識,我們的目的就是解決我們服務的遷移,那么接下去通過幾個案例來感受一下K8s部署帶來的便捷與效率。
環境准備:
3個節點,然后我這邊也安裝了 Ingress。
部署wordpress+mysql(Service:NodePort模式):
(1)創建wordpress命名空間
kubectl create namespace wordpress
kubectl get ns
(2)創建wordpress-db.yaml文件,根據wordpress-db.yaml創建資源[mysql數據庫]
apiVersion: apps/v1beta1 kind: Deployment metadata: name: mysql-deploy namespace: wordpress labels: app: mysql spec: template: metadata: labels: app: mysql spec: containers: - name: mysql image: mysql:5.6 imagePullPolicy: IfNotPresent ports: - containerPort: 3306 name: dbport env: - name: MYSQL_ROOT_PASSWORD value: rootPassW0rd - name: MYSQL_DATABASE value: wordpress - name: MYSQL_USER value: wordpress - name: MYSQL_PASSWORD value: wordpress volumeMounts: - name: db mountPath: /var/lib/mysql volumes: - name: db hostPath: path: /var/lib/mysql --- apiVersion: v1 kind: Service metadata: name: mysql namespace: wordpress spec: selector: app: mysql ports: - name: mysqlport protocol: TCP port: 3306 targetPort: dbport
kubectl apply -f wordpress-db.yaml
kubectl get pods -n wordpress
kubectl get svc mysql -n wordpress
kubectl describe svc mysql -n wordpress 記錄下 Endpoints的IP 或者IP ,需要配置到wordpress里面。
(3)創建wordpress.yaml文件,根據wordpress.yaml創建資源[wordpress]
apiVersion: apps/v1beta1 kind: Deployment metadata: name: wordpress-deploy namespace: wordpress labels: app: wordpress spec: template: metadata: labels: app: wordpress spec: containers: - name: wordpress image: wordpress imagePullPolicy: IfNotPresent ports: - containerPort: 80 name: wdport env: - name: WORDPRESS_DB_HOST value: 192.168.190.102:3306
- name: WORDPRESS_DB_USER value: wordpress - name: WORDPRESS_DB_PASSWORD value: wordpress --- apiVersion: v1 kind: Service metadata: name: wordpress namespace: wordpress spec: type: NodePort selector: app: wordpress ports: - name: wordpressport protocol: TCP port: 80 targetPort: wdport
kubectl apply -f wordpress.yaml #修改其中mysql的ip地址,其實也可以使用service的name:mysql
kubectl get pods -n wordpress
kubectl get svc -n wordpress # 獲取到轉發后的端口,如這里的30078
(6)訪問測試,win上訪問集群中任意宿主機節點的IP:30078
部署Spring Boot項目(Ingress):
流程:確定服務-->編寫Dockerfile制作鏡像-->上傳鏡像到倉庫-->編寫K8S文件-->創建
(1)准備Spring Boot項目springboot-demo
@RestController @RequestMapping("wuzz") public class TestController { @RequestMapping(value = "/k8s", method = {RequestMethod.GET}) public String k8s() { return "Hello Kubernetes ....."; } }
(2) mvn clean install生成xxx.jar,並且上傳到 linux 自定義目錄下(我這邊是 /mysoft)
(3)編寫Dockerfile文件 cd /mysoft 下 vi Dockerfile
FROM openjdk:8-jre-alpine COPY springboot-demo-1.0-SNAPSHOT.jar /mysoft/springboot-demo.jar ENTRYPOINT ["java","-jar","/mysoft/springboot-demo.jar"]
(4)根據Dockerfile創建image
docker build -t springboot-demo-image .
(5)使用docker run創建container
docker run -d --name s1 springboot-demo-image
(6)訪問測試
docker inspect s1
curl ip:8080/wuzz/k8s
(7)將鏡像推送到鏡像倉庫
# 登錄阿里雲鏡像倉庫
sudo docker login --username=隨風去wuzz registry.cn-hangzhou.aliyuncs.com
docker tag springboot-demo-image registry.cn-hangzhou.aliyuncs.com/wuzz-docker/springboot-demo-image:v1.0
docker push registry.cn-hangzhou.aliyuncs.com/wuzz-docker/springboot-demo-image:v1.0
推送完成。
(8)編寫Kubernetes配置文件vi springboot-demo.yaml
# 以Deployment部署Pod apiVersion: apps/v1 kind: Deployment metadata: name: springboot-demo spec: selector: matchLabels: app: springboot-demo replicas: 1 template: metadata: labels: app: springboot-demo spec: containers: - name: springboot-demo image: registry.cn-hangzhou.aliyuncs.com/wuzz-docker/springboot-demo-image:v1.0 ports: - containerPort: 8080
--- # 創建Pod的Service apiVersion: v1 kind: Service metadata: name: springboot-demo spec: ports: - port: 80 protocol: TCP targetPort: 8080 selector: app: springboot-demo --- # 創建Ingress,定義訪問規則,一定要記得提前創建好nginx ingress controller apiVersion: extensions/v1beta1 kind: Ingress metadata: name: springboot-demo spec: rules: - host: tomcat.wuzz.com http: paths: - path: / backend: serviceName: springboot-demo servicePort: 80
生成 pod :kubectl apply -f springboot-demo.yaml
(9)查看資源
kubectl get pods
kubectl get pods -o wide
curl 192.168.190.103:8080/wuzz/k8s
kubectl get svc
kubectl scale deploy springboot-demo --replicas=5
(10)win配置hosts文件[一定要記得提前創建好nginx ingress controller]
192.168.1.102 tomcat.wuzz.com
(11)win瀏覽器訪問
部署傳統分布式服務(user/order)及注冊中心(Nacos):
將user/order服務注冊到nacos,user服務能夠找到order服務。
(1).啟動兩個Spring Boot項目,兩者Pom.xml如下:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR1</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.10</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<!-- SpringCloud 所有子項目 版本集中管理. 統一所有SpringCloud依賴項目的版本依賴-->
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>0.9.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.1.6.RELEASE</version>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.1.6.RELEASE</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
application.properties :user端口8081,order9090,記得修改對應application.name
server.port=8081 spring.application.name=user spring.cloud.nacos.discovery.server-addr=192.168.1.101:8848
user 需要提供一個接口以供測試:
@RestController public class TestController { @Autowired private DiscoveryClient discoveryClient; @RequestMapping(value = "/k8s", method = {RequestMethod.GET}) public String insert() { List<ServiceInstance> list = discoveryClient.getInstances("order"); ServiceInstance serviceInstance = list.get(0); URI uri = serviceInstance.getUri(); System.out.println(uri); testUri(uri.toString()); return list.toString(); } public void testUri(String uri) { URL url = null; try { url = new URL(uri); URLConnection urlConnection = url.openConnection(); urlConnection.connect(); System.out.println("連接可用"); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
然后查看nacos server的服務列表:
為了驗證user能夠發現order的地址,訪問localhost:8081/k8s,查看日志輸出,從而測試是否可以ping通order地址
(2) 本地測試無誤以后將兩個項目打成 jar 包,丟到 linux 目錄中。編寫 Dockerfile 文件:
FROM openjdk:8-jre-alpine COPY user-1.0.0-SNAPSHOT.jar /user.jar ENTRYPOINT ["java","-jar","/user.jar"] ------- FROM openjdk:8-jre-alpine COPY order-0.0.1-SNAPSHOT.jar /order.jar ENTRYPOINT ["java","-jar","/order.jar"]
構建鏡像:
docker build -t user-image:v1.0 . docker build -t order-image:v1.0 .
將鏡像推送到遠程私人倉庫:我這里選擇了阿里雲
#打 tag docker tag user-image:v1.0 registry.cn-hangzhou.aliyuncs.com/wuzz-docker/user-image:v1.0 docker tag order-image:v1.0 registry.cn-hangzhou.aliyuncs.com/wuzz-docker/order-image:v1.0 #推送 docker push registry.cn-hangzhou.aliyuncs.com/wuzz-docker/user-image docker push registry.cn-hangzhou.aliyuncs.com/wuzz-docker/order-image
(3) 編寫 user.yaml ,order.yaml 文件:
user.yaml
# 以Deployment部署Pod apiVersion: apps/v1 kind: Deployment metadata: name: user spec: selector: matchLabels: app: user replicas: 1 template: metadata: labels: app: user spec: containers: - name: user image: registry.cn-hangzhou.aliyuncs.com/wuzz-docker/user-image:v1.0 ports: - containerPort: 8081
--- # 創建Pod的Service apiVersion: v1 kind: Service metadata: name: user spec: ports: - port: 80 protocol: TCP targetPort: 8081 selector: app: user --- # 創建Ingress,定義訪問規則,一定要記得提前創建好nginx ingress controller apiVersion: extensions/v1beta1 kind: Ingress metadata: name: user spec: rules: - host: k8s.demo.gper.club http: paths: - path: / backend: serviceName: user servicePort: 80
order.yaml:
# 以Deployment部署Pod apiVersion: apps/v1 kind: Deployment metadata: name: order spec: selector: matchLabels: app: order replicas: 1 template: metadata: labels: app: order spec: containers: - name: order image: registry.cn-hangzhou.aliyuncs.com/wuzz-docker/order-image:v1.0 ports: - containerPort: 9090
--- # 創建Pod的Service apiVersion: v1 kind: Service metadata: name: order spec: ports: - port: 80 protocol: TCP targetPort: 9090 selector: app: order
(4) 構建 pods :kubectl apply -f user.yaml
kubectl get pods 查看pods
kubectl get pods -o wide 查看pods詳情
kubectl get svc 查看service
kubectl get ingress 查看ingress網絡
這個時候我通過:kubectl logs -f <pod-name> [主要是為了看日志輸出,證明user能否訪問order] 發現這個pod報錯了,連接不上,經過測試 在本地跟直接在linux上通過java -jar 運行都是可以注冊的 ,沒問題。
這個時候我們可以 docker exec -it containerId /bin/sh 進入對用容器 ping 一下 這里報錯的地址,發現 ping 不通。這個時候獲取到對應的 pod 的 IP:
在節點 192.168.190.114 增加一條路由規則:/sbin/iptables -t nat -I POSTROUTING -s 192.168.190.0/24 -j MASQUERADE
然后會發現注冊成功:
可以發現,注冊到nacos server上的服務ip地址為pod的ip,比如192.168.190.114/192.168.190.115 .
(5) 測試:通過瀏覽器訪問我們配置的 Ingress 的對應路徑
看一下 pod 的日志發現調用沒問題。如果服務都是在K8s集群中,最終將pod ip注冊到了nacos server,那么最終服務通過pod ip發現。
假如user現在不在K8s集群中,order在K8s集群中:
比如user使用本地idea中的,order使用上面K8s中的 。
- 啟動本地idea中的user服務
- 查看nacos server中的user服務列表
- 訪問本地的localhost:8081/ks,並且觀察idea中的日志打印,發現訪問的是order的pod id,此時肯定是不能進行服務調用的,怎么解決呢?
之所以訪問不了,是因為order的pod ip在外界訪問不了,怎么解決呢?
- 可以將pod啟動時所在的宿主機的ip寫到容器中,也就是pod id和宿主機ip有一個對應關系
- pod和宿主機使用host網絡模式,也就是pod直接用宿主機的ip,但是如果服務高可用會有端口沖突問題[可以使用pod的調度策略,盡可能在高可用的情況下,不會將pod調度在同一個worker中]
我們來演示一個host網絡模式的方式,修改order.yaml文件,修改之后apply之前可以看一下各個節點的9090端口是否被占用
apiVersion: apps/v1 kind: Deployment metadata: name: order spec: selector: matchLabels: app: order replicas: 1 template: metadata: labels: app: order spec:
#主要是加上host映射 hostNetwork: true containers: - name: order image: registry.cn-hangzhou.aliyuncs.com/wuzz-docker/order-image:v1.0 ports: - containerPort: 9090 --- # 創建Pod的Service apiVersion: v1 kind: Service metadata: name: order spec: ports: - port: 80 protocol: TCP targetPort: 9090 selector: app: order
構建之前記得把之前哪個刪掉:kubectl apply -f order.yaml
kubectl get pods -o wide --->找到pod運行在哪個機器上,比如w2,查看w2上的9090端口是否啟動
構建完,啟動本地的user服務,看是否注冊上去:
訪問本地發 user服務:
查看控制台的輸出信息: