写在前面 接下来我们尝试在完整集群上部署微服务,首先来复习之前的一些命令以及学习一个新的命令,了解这些对于学习和熟悉Kubernetes有非常大的帮助。
新的命令 首先查看一下当前其他节点的运行状态信息,可以看到它们都是Ready状态:
1 2 3 4 [root@server02 ~]# kubectl get node NAME STATUS ROLES AGE VERSION 192.168.51.121 Ready <none> 4h v1.9.0 192.168.51.123 Ready <none> 4h v1.9.0
再来查看一下services,可以看到这里有一个Kubernetes默认的services:
1 2 3 [root@server02 ~]# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.68.0.1 <none> 443/TCP 1d
再来查看一下pods,正常应该就是没有的:
1 2 [root@server02 ~]# kubectl get pods No resources found.
接下来我们尝试通过kubectl run
命令在k8s集群中部署一个命名为kubernetes-bootcamp
的应用,Docker镜像通过--image
指定,--port
设置应用对外服务的端口,使用的命令如下:
1 2 [root@server02 ~]# kubectl run kubernetes-bootcamp --image=jocatalin/kubernetes-bootcamp:v1 --port=8080 deployment "kubernetes-bootcamp" created
然后我们查看一下当前所有的deployments:
1 2 3 [root@server02 ~]# kubectl get deploy NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE kubernetes-bootcamp 1 1 1 1 41s
才是再来查看一下pods,可以发现这里就创建了一个pods:
1 2 3 [root@server02 ~]# kubectl get pods NAME READY STATUS RESTARTS AGE kubernetes-bootcamp-6b7849c495-ssf78 1/1 Running 0 1m
然后我们尝试查看一下某个pods中的运行日志信息,可使用kubectl logs +pods名称
命令来进行查看:
1 2 [root@server02 ~]# kubectl logs kubernetes-bootcamp-6b7849c495-ssf78 Kubernetes Bootcamp App Started At: 2021-09-04T13:12:56.352Z | Running On: kubernetes-bootcamp-6b7849c495-ssf78
也可以借鉴docker logs命令,在上述kubectl logs命令后面添加-f
参数来跟踪日志,这样一旦有刷新日志就会实时的刷新出来:
1 [root@server02 ~]# kubectl logs kubernetes-bootcamp-6b7849c495-ssf78 -f
我们再来查看一下这个pods的详细信息,如下所示:
1 [root@server02 ~]# kubectl describe pods kubernetes-bootcamp-6b7849c495-ssf78
可以看到它多了一个Mounts的配置信息,值为/var/run/secrets/kubernetes.io/serviceaccount
,然后我们可以使用类似于docker中的exec命令来以终端方式进入到该pods中:
1 2 3 4 5 6 7 8 9 10 [root@server02 ~]# kubectl exec -it kubernetes-bootcamp-6b7849c495-ssf78 bash root@kubernetes-bootcamp-6b7849c495-ssf78:/# ls -l /var/run/secrets/kubernetes.io/serviceaccount total 0 lrwxrwxrwx 1 root root 13 Sep 4 13:12 ca.crt -> ..data/ca.crt lrwxrwxrwx 1 root root 16 Sep 4 13:12 namespace -> ..data/namespace lrwxrwxrwx 1 root root 12 Sep 4 13:12 token -> ..data/token root@kubernetes-bootcamp-6b7849c495-ssf78:/# cd /var/run/secrets/kubernetes.io/serviceaccount root@kubernetes-bootcamp-6b7849c495-ssf78:/var/run/secrets/kubernetes.io/serviceaccount# ls ca.crt namespace token root@kubernetes-bootcamp-6b7849c495-ssf78:/var/run/secrets/kubernetes.io/serviceaccount#
可以看到这个/var/run/secrets/kubernetes.io/serviceaccount
其实是一个目录,里面有三个文件,ca.crt是根证书文件,namespace的值为default,以及一个token文件。这些值是怎么来的呢?通过前面的学习可以知道它是与serviceaccount相关联的值。接下来我们看看当前是否存在serviceaccount,使用命令如下:
1 2 3 [root@server02 ~]# kubectl get serviceaccount NAME SECRETS AGE default 1 1d
也可以使用简写命令:
1 2 3 [root@server02 ~]# kubectl get sa NAME SECRETS AGE default 1 1d
可以看到这里有一个默认的名为default的namespace,可以使用如下命令来查看它的详细信息,其中-o
指令用于指定输出的格式,这里我们让信息以yaml格式进行输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 [root@server02 ~]# kubectl get sa -o yaml apiVersion: v1 items: - apiVersion: v1 kind: ServiceAccount metadata: creationTimestamp: 2022-09-03T10:56:39Z name: default namespace: default resourceVersion: "142" selfLink: /api/v1/namespaces/default/serviceaccounts/default uid: 16487d73-2b77-11ed-85ff-000c29e3dc2b secrets: - name: default-token-tq5m2 kind: List metadata: resourceVersion: "" selfLink: ""
你要是以json格式进行输出,这也是可以的。可以看到上面有一个名为secrets.name
的配置项,它的值为default-token-tq5m2。开发者也可以使用如下命令查看一下当前所有的secrets:
1 2 3 [root@server02 ~]# kubectl get secrets NAME TYPE DATA AGE default-token-tq5m2 kubernetes.io/service-account-token 3 1d
然后我们查看一下这个secrets的内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 [root@server02 ~]# kubectl get secrets -o yaml apiVersion: v1 items: - apiVersion: v1 data: ca.crt: ca.crt文件的内容 namespace: ZGVmYXVsdA== token: token的值 kind: Secret metadata: annotations: kubernetes.io/service-account.name: default kubernetes.io/service-account.uid: 16487d73-2b77-11ed-85ff-000c29e3dc2b creationTimestamp: 2021-09-03T10:56:39Z name: default-token-tq5m2 namespace: default resourceVersion: "139" selfLink: /api/v1/namespaces/default/secrets/default-token-tq5m2 uid: 164a148f-2b77-11ed-85ff-000c29e3dc2b type: kubernetes.io/service-account-token kind: List metadata: resourceVersion: "" selfLink: ""
这其实就和我们之前在/var/run/secrets/kubernetes.io/serviceaccount
目录中所看到的三个文件是一一对应的,相当于将这个secret赋给了每一个pod。这就说明如果APIServer的kube-apiserver.service
文件中的admission-control
配置项,如果配置了ServiceAccount,那么它就会在default这个namespace下创建一个默认的serviceaccount,然后每个pod在启动的时候会将这个service中的secret以文件的形式挂载到pod中。有了这些挂载的文件之后,我们的pod就可以通过https的方式去访问APIServer,也就是说让pod可以通过APIServer的认证。
接下来继续学习Kubernetes,回到/home/envy/services
目录,可以看到里面有三个文件,这是之前我们创建的三个用于配置对应信息的文件:
1 2 3 4 [root@server02 services]# ls -l /home/envy/services/ -rw-r--r-- 1 root root 274 8月 31 21:51 nginx-deployment.yaml -rw-r--r-- 1 root root 151 8月 31 21:24 nginx-pod.yaml -rw-r--r-- 1 root root 174 9月 2 21:47 nginx-service.yaml
之前我们创建对应的deployment、pod和service时,使用了kubectl create
命令,接下来我们尝试使用新的命令kubectl apply
。我们利用kubectl apply
来创建一个pod:
1 2 [root@server02 services]# kubectl apply -f nginx-pod.yaml pod "nginx" created
再来看一下当前所有的pod:
1 2 3 4 [root@server02 services]# kubectl get pods NAME READY STATUS RESTARTS AGE kubernetes-bootcamp-6b7849c495-ssf78 1/1 Running 0 1h nginx 1/1 Running 0 4m
然后查看一下名为nginx的pod的详细信息:
1 [root@server02 services]# kubectl describe pods nginx
可以看到相比于kubectl create命令,它多了一个Annotations,里面记录的是最近一次的修改,会将修改的内容添加到里面,你会发现这个命令并没有将完整的修改内容都显示全,如果你想显示完全,可以使用如下命令:
1 2 3 4 5 [root@server02 ~]# kubectl get pods nginx -o json "annotations": { "kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\"annotations\":{},\"name\":\"nginx\",\"namespace\":\"default\"},\"spec\":{\"containers\":[{\"image\":\"nginx:1.7.9\",\"name\":\"nginx\",\"ports\":[{\"containerPort\":80}]}]}}\n" }, ......
可以看到这里面是我们上一次应用的完整配置,它起到了一个记录的功能,会将最近一次文件的配置内容放到annotations中进行存储,这样当应用出现问题的时候,它作为应用回滚的依据。还有一个区别,就是在使用kubectl create
命令的时候,如果应用已经存在,那么必须将该应用删除,才能重新创建。而kubectl apply
命令并不会重新去创建应用,而是会在之前应用的基础上进行修改。
举个例子,我们想创建一个基于nginx1.13版本的nginx-pod,此时该如何操作呢?可以使用kubectl apply
命令,首先将nginx-pod.yaml
文件中的nginx镜像版本由1.7.9修改为1.13:
1 2 3 4 5 6 7 8 9 10 apiVersion: v1 kind: Pod metadata: name: nginx spec: containers: - name: nginx image: nginx:1.13 ports: - containerPort: 80
接着执行如下命令来创建nginx-pod:
1 2 [root@server02 services]# kubectl apply -f nginx-pod.yaml pod "nginx" configured
然后使用如下命令来查看一下是否真的更新成功:
1 2 3 4 5 6 [root@server02 services]# kubectl get pods nginx -o json "metadata": { "annotations": { "kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\"annotations\":{},\"name\":\"nginx\",\"namespace\":\"default\"},\"spec\":{\"containers\":[{\"image\":\"nginx:1.13\",\"name\":\"nginx\",\"ports\":[{\"containerPort\":80}]}]}}\n" }, ......
当然了,更新镜像还有之前使用的方式:
1 2 [root@server02 services]# kubectl set image pods nginx nginx=nginx:1.7.9 pod "nginx" image updated
再来看一下容器中的镜像,可以看到此时容器中的镜像已经变成1.7.9,但是Annotations中显示的镜像版本还是1.13,这是因为这个Annotations中始终保持的是配置文件中最新的配置,而无论开发者使用命令做任何修改,Annotations中始终都不会进行显示,这里只会显示配置文件中的修改。
接下来我们使用kubectl apply
来创建nginx-deployment和nginx-service这两个:
1 2 3 4 [root@server02 services]# kubectl apply -f nginx-deployment.yaml deployment "nginx-deployment" created [root@server02 services]# kubectl apply -f nginx-service.yaml service "nginx-service" created
接下来我们尝试使用NodeIP+NodePort方式来访问其他的Node节点,这是可以访问的:
1 2 3 4 [root@server02 services]# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.68.0.1 <none> 443/TCP 2d nginx-service NodePort 10.68.199.24 <none> 8080:20000/TCP 4m
然后我们使用另一种方式,就是通过进入到容器中使用CLUSTER_IP+ServicePort这一方式来访问。由于这里需要进入到一个容器中,如果现在没有容器,可以使用kubectl run busybox --rm=true --image=busybox --restart=Never --tty -i
来启动一个busybox镜像,这个镜像是专门用于测试,它启动完之后提供一些命令,就相当于运行在这个集群中的一个沙盒。 --rm=true
参数表示在结束的时候会自动删除,--image=busybox
用于指定镜像为busybox,--restart=Never
表示重启方案,此处设置从来不重启,即退出后就不重启。--tty
表示开启一个伪终端, -i
表示获取到标准输入。
1 2 3 4 5 6 [root@server02 services]# kubectl run busybox --rm=true --image=busybox --restart=Never --tty -i If you don't see a command prompt, try pressing enter. / # / # / # ls bin dev etc home proc root sys tmp usr var
这样我们就进入了这个容器,我们可以使用wget命令,将wget输出定位到标准输出中,然后我们使用CLUSTER_IP+ServicePort这一方式来访问:
1 / # wget -qO - 10.68.199.24:8080
如果出现nginx相关的页面信息,这就说明kube-proxy是正常的,然后我们将上面的IP修改为services的命令看看是否也能成功访问:
1 / # wget -qO - nginx-service:8080
如果也出现nginx相关的页面信息,这就说明kube-dns也是正常的。
微服务项目部署 思路分析
消息服务:message-service
课程dubbo服务:course-dubbo-service
课程web服务:course-edge-service
用户thrift服务:user-thrift-service
用户web服务:user-edge-service
API网关:api-gateway
如果将它们放到kunernetes集群中运行,我们需要考虑哪些问题呢?(1)哪些服务适合单独成一个pod?哪些服务适合在一个pod中? 在Kubernetes中,最小的单元是pod,一个pod中可以包含一个或者多个容器,因此我们需要考虑我们有哪些服务是适合放在同一个pod中,还有哪些是适合单独成一个pod。如果将多个服务放在一个pod中,会有什么特征呢?毫无疑问两者之间的访问效率肯定是很高的,它们之间通过本机localhost就可以访问到处于同一个pod中的服务。
消息服务与其他的服务关联程度不大,而且所有的服务都可能去调用消息服务,因此它和谁放在一起都不太合适,可以将其单独做成一个pod。然后课程的dubbo服务和web服务这两个是紧密相关的,因为课程的dubbo服务大部分都是由web服务去调用的,两者的交换频率肯定会很高。因此课程的dubbo服务和web服务这两个可以放在同一个pod中。同理用户的thrift服务和web服务也应该放在同一个pod中。api网关可能会调用很多的服务,因此它并不适合和其他的服务放在一起,所以将其放在一个单独的pod中。
(2)在一个pod里面的服务如何彼此访问?它们的服务如何对外提供服务? 举个例子,如课程的dubbo服务和web服务,它们都在同一个pod中,两者是如何进行彼此通信的呢?可以通过本机的端口直接去访问,这是没问题的。在前面我们学习过service,知道我们的服务可以通过CLUSTER_IP或者通过kube-dns根据名字来进行解析,让我们的服务可以在集群内部进行访问,并且在一个service中可以同时定义多个端口,其实就是允许我们同时对外提供多个服务。这一点从技术上来说也是没有任何问题的。
(3)单独的pod如何对外提供服务? 单独的pod其实就更简单了,直接通过CLUSTER_IP或者通过kube-dns根据名字来进行解析,就可以直接提供集群内的服务了。
(4)哪个服务作为整个服务的入口,入口服务如何对外提供服务? 最后比较特殊的就是API网关,它作为整个服务的入口,为了对外提供服务,它需要提供一个NodePort,这样就让我们在集群外,也可以访问到这个服务,这就是api-gateway需要对外提供服务的方式,即它需要使用到NodePort。
搞定配置 配置的模板已经设置好了,就是按照前面所说的服务划分,但是开发者还需要做一些配置,将这些配置文件中的变量进行配置。进入到主节点中,我们先进入到如下目录:
1 $ cd /home/envy/kubernetes-starter/service-config/
然后查看一下当前的目录文件信息:
1 2 3 4 5 $ ls api-gateway.yaml message-service.yaml course-service.yaml user-service.yaml #替换变量 - (hub.envyzhan.com:9080是我的环境的镜像仓库地址,大家修改为各自的仓库) $ sed -i 's/{{HUB}}/hub.envyzhan.com:9080/g' *
接下来查看各个文件的信息,api-gateway.yaml
配置文件内容如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 apiVersion: v1 kind: Service metadata: labels: app: api-gateway name: api-gateway spec: ports: - port: 80 protocol: TCP targetPort: 8080 nodePort: 80 selector: app: api-gateway type: NodePort --- apiVersion: apps/v1beta1 kind: Deployment metadata: name: api-gateway-deployment spec: replicas: 1 template: metadata: labels: app: api-gateway spec: containers: - name: api-gateway image: hub.envyzhan.com:9080/micro-service/api-gateway-zuul:latest ports: - containerPort: 8080
接着我们再来看一下message-service.yaml
配置文件的内容,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 apiVersion: v1 kind: Service metadata: labels: app: message-service name: message-service spec: ports: - port: 9090 protocol: TCP targetPort: 9090 selector: app: message-service type: ClusterIP --- apiVersion: apps/v1beta1 kind: Deployment metadata: name: message-service-deployment spec: replicas: 1 template: metadata: labels: app: message-service spec: containers: - name: message-service image: hub.envyzhan.com:9080/micro-service/message-service:latest ports: - containerPort: 9090
可以看到这个Service的类型是ClusterIP,因为它不需要对外提供服务,只需在集群内提供服务。
再来看一下course-service.yaml
配置文件的内容,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 apiVersion: v1 kind: Service metadata: labels: app: course-service name: course-service spec: ports: - port: 8081 protocol: TCP targetPort: 8081 selector: app: course-service type: ClusterIP --- apiVersion: apps/v1beta1 kind: Deployment metadata: name: course-service-deployment spec: replicas: 1 template: metadata: labels: app: course-service spec: containers: - name: course-service image: hub.envyzhan.com:9080/micro-service/course-service:latest ports: - containerPort: 20880 - name: course-edge-service image: hub.envyzhan.com:9080/micro-service/course-edge-service:latest ports: - containerPort: 8081
可以看到里面有两个容器,一个是course-service,容器端口为20880,另一个则是course-edge-service,容器端口为8081,这个与名为course-service的service所指定的service端口是一致的。这是因为这个8081是在集群内提供给其他服务所使用的,而这个20880它只需要给这个course-edge-service使用就可以,因为别的服务并没有使用到它,也没有依赖它,因此上面我们只需指定一个端口。
最后再来看一下这个user-service.yaml
配置文件的内容,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 apiVersion: v1 kind: Service metadata: labels: app: user-service name: user-service namespace: default spec: ports: - name: user-edge-service-port port: 8082 protocol: TCP targetPort: 8082 - name: user-service-port port: 7911 protocol: TCP targetPort: 7911 selector: app: user-service sessionAffinity: None type: ClusterIP --- apiVersion: apps/v1beta1 kind: Deployment metadata: name: user-service-deployment spec: replicas: 1 template: metadata: labels: app: user-service spec: containers: - name: user-service image: hub.envyzhan.com:9080/micro-service/user-service:latest ports: - containerPort: 7911 - name: user-edge-service image: hub.envyzhan.com:9080/micro-service/user-edge-service:latest ports: - containerPort: 8082
可以看到这个名为user-service的service里面提供了两个port,一个是user-edge-service-port,端口号为8082;另一个则是user-service-port,端口号为7911,注意定义多个port时就需要开发者指定名称。一个是方便我们记忆,另一个则是方便后来维护的人,这些port分别用于做什么事情。这就表明这两个port在集群中,都是提供给集群内其他port来使用的。后面的user-service-deployment中也是有两个容器,一个是user-service,另一个则是user-edge-service。
可以看到user-service和course-service这两个service的唯一区别在于,course-service只定义了一个端口用于对外提供服务,而user-service却需要提供两个端口,且这两个端口都需要对外提供服务。
启动服务 (1)启动Harbor。由于在前面我们已经将harbor设置为开机自启动,因此这里会自己启动。 (2)启动MySQL。进入到/opt/mysql
目录,在里面执行其中的start.sh
脚本文件即可启动MySQL。 (3)启动Redis。进入到/opt/redis
目录,在里面执行其中的start.sh
脚本文件即可启动Redis。 (4)启动Zookeeper。由于在前面我们已经将Zookeeper设置为开机自启动,因此这里会自己启动。
梳理代码 (1)api-gateway-zuul微服务配置信息改造。 api-gateway-zuul微服务原有的配置信息如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 # 服务名称和端口号 server: name: gateway-zuul-service port: 8080 # zuul相关配置信息 zuul: routes: course: path: /course/** url: http://course-edge-service:8023/course/ user: path: /user/** url: http://user-edge-service:8022/user/
修改之后的application.yml
配置文件的信息为:
1 2 3 4 5 6 7 8 9 10 11 12 13 # 服务名称和端口号 server: name: gateway-zuul-service port: 8080 # zuul相关配置信息 zuul: routes: course: path: /course/** url: http://course-service:8081/course/ user: path: /user/** url: http://user-service:8082/user/
(2)course-dubbo-service微服务配置信息改造。 course-dubbo-service微服务原有的配置信息如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 # 用户服务的IP和端口号 thrift: user: ip: user-service port: 7911 # 数据源的配置信息 spring: datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://192.168.51.100:3306/db_course username: root password: envy123 # dubbo相关配置 dubbo: application: name: course-service registry: address: zookeeper://192.168.51.100:2181 protocol: name: dubbo port: 20880 # host: 192.168.51.6 scan: base-packages: com.envy.course
通过对比发现这个服务的配置信息无需进行修改。(3)course-edge-service微服务配置信息改造。 course-edge-service微服务原有的配置信息如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 # 服务名称和端口号 server: name: course-edge-service port: 8023 # dubbo相关配置 dubbo: application: name: course-service registry: address: zookeeper://${zookeeper.url}:2181 protocol: name: dubbo port: 20880 # host: 192.168.51.6 scan: base-packages: com.envy.course
修改之后的application.yml
配置文件的信息为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 # 服务名称和端口号 server: name: course-edge-service port: 8023 # dubbo相关配置 dubbo: application: name: course-service registry: address: zookeeper://192.168.51.100:2181 protocol: name: dubbo port: 20880 scan: base-packages: com.envy.course user: edge: service: addr: user-service:8082
(4)user-edge-service微服务配置信息改造。 user-edge-service微服务原有的配置信息如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 # 服务名称和端口号 server: name: user-edge-service port: 8022 # 用户服务的IP和端口号 thrift: user: ip: user-service port: 7911 # 短信服务的IP和端口号 message: ip: message-service port: 9090 # Redis配置信息 spring: redis: host: ${redis.url} port: 6379 timeout: 30000
修改之后的application.yml
配置文件的信息为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 # 服务名称和端口号 server: name: user-edge-service port: 8022 # 用户服务的IP和端口号 thrift: user: ip: user-service port: 7911 # 短信服务的IP和端口号 message: ip: message-service port: 9090 # Redis配置信息 spring: redis: host: 192.168.51.100 port: 6379 timeout: 30000
(5)user-thrift-service微服务配置信息改造。 user-thrift-service微服务原有的配置信息如下:
1 2 3 4 5 6 7 8 9 10 11 # 服务名称和端口号 server: name: user-thrift-service port: 7911 # 数据源的配置信息 spring: datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://${mysql.url}:3306/db_user username: root password: envy123
修改之后的application.yml
配置文件的信息为:
1 2 3 4 5 6 7 8 9 10 11 # 服务名称和端口号 server: name: user-thrift-service port: 7911 # 数据源的配置信息 spring: datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://192.168.51.100:3306/db_user username: root password: envy123
重新打包镜像 将下来我们需要将之前我们修改过配置文件的服务,都重新打包成镜像,这个过程在前面都已经进行了介绍,这里就不过多介绍了。
删除现有的服务 首先进入到主节点,查看一下当前所有的服务:
1 2 3 4 [root@server02 service-config]# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.68.0.1 <none> 443/TCP 3d nginx-service NodePort 10.68.199.24 <none> 8080:20000/TCP 1d
考虑到后面这个nginx-service可能会影响到现有的服务,这里我们将这个服务给删除掉:
1 2 [root@server02 service-config]# kubectl delete svc nginx-service service "nginx-service" deleted
同理查看一下当前所有的deployments:
1 2 3 4 [root@server02 service-config]# kubectl get deploy NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE kubernetes-bootcamp 1 1 1 1 2d nginx-deployment 2 2 2 2 1d
删除上述两个deployment:
1 2 3 4 [root@server02 service-config]# kubectl delete deploy nginx-deployment deployment "nginx-deployment" deleted [root@server02 service-config]# kubectl delete deploy kubernetes-bootcamp deployment "kubernetes-bootcamp" deleted
再来查看一下当前所有的pods:
1 2 3 [root@server02 service-config]# kubectl get pods NAME READY STATUS RESTARTS AGE nginx 1/1 Running 0 1d
删除这个名为nginx的pod:
1 2 [root@server02 service-config]# kubectl delete pod nginx pod "nginx" deleted
接着进入到主节点所在机器,我们需要在它的/etc/hosts
文件中新增一条映射信息:
1 192.168.51.100 hub.envyzhan.com
然后我们进入到/home/envy/kubernetes-starter/service-config
目录,开始根据对应的配置文件创建对应的Service、Deployment。注意它们是有依赖关系的,因此创建顺序不能搞错,必须是【message-service.yaml】–>【user-service.yaml】–>【course-service.yaml】–>【api-gateway.yaml】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 [root@server02 service-config]# kubectl apply -f message-service.yaml service "message-service" created deployment "message-service-deployment" created [root@server02 service-config]# kubectl apply -f user-service.yaml service "user-service" created deployment "user-service-deployment" created [root@server02 service-config]# kubectl apply -f course-service.yaml service "course-service" created deployment "course-service-deployment" created [root@server02 service-config]# kubectl apply -f api-gateway.yaml deployment "api-gateway-deployment" created The Service "api-gateway" is invalid: spec.ports[0].nodePort: Invalid value: 80: provided port is not in the valid range. The range of valid ports is 20000-40000
可以看到我们在创建api-gateway这一NodePort时出现问题,原因是我们在APIServer中规定了节点端口必须在2万-4万之间,而此处的80端口是不在里面,所以就抛出异常。此时我们可以修改APIServer的配置信息:
1 [root@server02 service-config]# vi /lib/systemd/system/kube-apiserver.service
我们可以将其中的2万-4万修改为80-4万,这样就好了,当然你可以让api-gateway它的NodePort修改为2万-4万之间的值,只是此时用起来就不太方便了。之后依次执行如下命令来重启APIServer:
1 2 [root@server02 service-config]# systemctl daemon-reload [root@server02 service-config]# systemctl restart kube-apiserver
之后我们再次重新执行上述kubectl apply -f api-gateway.yaml
命令,可以看到此时就不抛出异常了:
1 2 3 [root@server02 service-config]# kubectl apply -f api-gateway.yaml service "api-gateway" created deployment "api-gateway-deployment" unchanged
接着我们查看一下当前所有的service信息:
1 2 3 4 5 6 7 [root@server02 service-config]# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE api-gateway NodePort 10.68.180.221 <none> 80:80/TCP 22s course-service ClusterIP 10.68.54.94 <none> 8081/TCP 7m kubernetes ClusterIP 10.68.0.1 <none> 443/TCP 3d message-service ClusterIP 10.68.24.72 <none> 9090/TCP 7m user-service ClusterIP 10.68.77.158 <none> 8082/TCP,7911/TCP 7m
再来查看一下当前所有的deployments:
1 2 3 4 5 6 [root@server02 service-config]# kubectl get deploy NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE api-gateway-deployment 1 1 1 0 8m course-service-deployment 1 1 1 0 9m message-service-deployment 1 1 1 0 9m user-service-deployment 1 1 1 0 9m
可以看到现在AVAILABLE的个数为0,表示一个都无法使用。那我们查看当前所有的pod信息:
1 2 3 4 5 6 [root@server02 service-config]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE api-gateway-deployment-68f4694877-2s8nv 0/1 ImagePullBackOff 0 14m 172.20.188.9 192.168.51.121 course-service-deployment-ff6f7d4b8-snm7l 0/2 ImagePullBackOff 0 14m 172.20.40.198 192.168.51.123 message-service-deployment-64c49f8ff8-48r8g 0/1 ImagePullBackOff 0 14m 172.20.188.7 192.168.51.121 user-service-deployment-8674c798b7-8bbck 0/2 ImagePullBackOff 0 14m 172.20.188.8 192.168.51.12
可以看到原来它们都在拉取镜像,这个速度有点慢。为了保险起见,接下来我们查看一下日志:
1 2 [root@server02 service-config]# kubectl logs -f api-gateway-deployment-68f4694877-2s8nv Error from server (BadRequest): container "api-gateway" in pod "api-gateway-deployment-68f4694877-2s8nv" is waiting to start: trying and failing to pull image
可以看到镜像拉取失败,我们尝试登陆到harbor镜像仓库上docker login http://hub.envyzhan.com:9080
,可以看到错误信息如下:
1 Error response from daemon: Get "https://hub.envyzhan.com:9080/v2/": http: server gave HTTP response to HTTPS client
在主节点上的/etc/docker/daemon.json
文件中新增一个不安全镜像仓库的配置信息,注意值必须是数组形式:
1 2 3 {"registry-mirrors": ["http://f1361db2.m.daocloud.io"], "insecure-registries": ["hub.envyzhan.com:9080"] }
然后我们依次执行如下命令来重新启动docker:
1 2 [root@server02 docker]# systemctl daemon-reload [root@server02 docker]# systemctl restart docker
之后我们再重新执行上述kubectl apply -f
命令。