准备工作
对k8s知识有一定了解掌握,能够明白Pod、Deployment、Service、Ingress 具体概念
准备一套可用的k8s环境
准备一个部署的spring boot 应用
构建&上传镜像
k8s最小单元是Pod, 而Pod 是一组运行的容器,那么容器是怎么运行起来的呢 ? 就是通过构建的镜像。(目前我们使用的容器技术都是基于docker)
那先让我们来一起制作个镜像,
将一个可运行的项目打包成一个jar文件,创建一个文件DockerFile,DockerFile和jar放到同一个目录 编写DockerFile
FROM java:8 #定义使用环境信息
WORKDIR /app/spring-boot-hello/ # 创建工作目录
ADD spring-boot-hello-1.0.jar /app/spring-boot-hello/ #把jar文件放到工作目录
EXPOSE 8080 #申明端口,并不是访问端口
ENTRYPOINT ["java","-jar","spring-boot-hello-1.0.jar"] #执行命令
执行生成镜像命令
docker build -f ./DockerFile -t "/test/helloworld-server:v1" .
查看镜像 docker images
运行镜像是否正常 9000为宿主机访问端口
docker run -p 9000:8080 /test/helloworld-server:v1
通过curl或者浏览器访问 localhost:9000 服务是否正常,如果正常说明镜像制作成功,开始准备把镜像上传到仓库, 上传之前确定是否登录,如果没有登录执行 :docker login 仓库地址
如果仓库使用的是harbor tag的名字格式改为:
仓库地址/仓库/名称,
比如 harbor.com/test/helloword-service
修改镜像 tag
docker tag <imageid> reg.com/test/helloworld-server:v1
上传镜像
docker push reg.com/test/helloworld-server:v1
上传完镜像可以登录仓库查看是否上传成功。
部署到k8s
创建deployment
创建deployment.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: helloworld-server
labels:
app: helloworld-server
spec:
# 副本数
replicas: 2
selector:
matchLabels:
app: helloworld-server
template:
metadata:
labels:
app: helloworld-server
spec:
containers:
- name: helloworld-server
image: reg.com/test/helloworld-server:v1
workingDir: /app/spring-boot-hello
ports:
- containerPort: 8080
执行 kubectl apply -f deployment.yaml
查看pod 是否创建成功 处于ready 状态
kubectl get pod -o wide
如果没有创建成功,通过log 或者 describe 查看具体原因
kubectl describe pod pod-namexxxxx
pod 的IP重启之后就会有变化,所以为了能够固定访问pod有了service的概念,pod绑定service,我们通过service来访问pod,service可以理解为集群内部的负载均衡流量的控制器,接下来我们开始创建service
创建service
创建service.ymal
apiVersion: v1
kind: Service
metadata:
name: helloworld-server
labels:
app: helloworld-server
spec:
type: NodePort
selector:
app: helloworld-server # pod app: helloworld-server
ports:
- port: 80
targetPort: 8080 # containerPort
我们使用的service type是NodePort,yaml里没有申明nodePort 所以k8s会默认创建一个nodePort (30000-40000),然后我们通过node ip 加 nodePort 就可以访问service。
kubectl apply -f service.yaml
查看nodePort kubectl get svc -o -wide
通过curl node ip : nodePort 查看是否路由到pod的服务,service的路由是针对内部使用,所以对外我们还需要提供另一种访问方式 那就是Ingress,(还有其它访问方式,本章使用Ingress)接下俩就是创建Ingress
创建Ingress
ingress.ymal
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: helloworld-server
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
rules:
- host: helloserver.com
http:
paths:
- path: /?(.*)
backend:
serviceName: helloworld-server # service name
servicePort: 80 # service port
kubectl apply -f ingress.ymal
安装ingress contoller
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-0.32.0/deploy/static/provider/baremetal/deploy.yaml
查看ingress contoller pod 是否创建成功,一般情况pull镜像的时候会失败,需要手动 docker pull .
配置host nodeIP helloserver.com,通过 curl helloserver.com:ingress contoller nodePort 访问。可以配置HA proxy 解决不用加端口问题
查看ingress contoller nodePort
kubectl get svc -o -wide -n ingress-nginx
到目前为止整个访问流程就配置完成了,如果我们配置完之后仍然访问不了
,可以一步一步的排除
绑定关系
- Service selector 应该匹配 Pod 的标签
- Service targerPort应该匹配在 Pod 内容器的containerPort
- Service 端口可以是任意数字。多个 Service 可以使用同个端口,因为它们已经分配了不同的 IP 地址
- Ingress 的servicePort应该匹配在 Service 中的port
- Service 的名称应该匹配在 Ingress 中的serviceName的字段
故障排查
检查pod是否正常
kubectl describe pod <pod name>
检查service 绑定pod配置是否正确 从service 访问pod Endpoints
kubectl describe service <service-name> | grep Endpoints
一个 endpoint 是一对<ip address:port>,并且当 Service(至少)target 一个 pod 时。至少有一对
检查Ingress 配置
kubectl describe ingress <ingress-name>
如果你能在 /Backend/ 列中看到 endpoint,但依旧无法访问应用程序,那么可能是以下问题:
- 你将 Ingress 暴露于公网的方式
- 你将集群暴露于公网的方式
总结
如果你毫无头绪,那么在 Kubernetes 中进行故障排除可能是一项艰巨的任务。
你应该永远记住以从下至上的顺序解决问题:现检查 Pod,然后向上移动堆栈至 Service 和 Ingress。