在 Kubernetes 中部署应用程序

在完成了本地 Kubernetes 的快速搭建(基于 Docker)后,我们已经可以正式的使用它了。对于我们平时最常见的需求,那就是往 Kubernetes 里部署应用程序,如果你没有看过 Kubernetes 相关的知识,这时候你可能会六神无主,但问题不大,我们就可以使用最经典的 Nginx 来小试身手。

创建 Deployment

创建 nginx-deployment.yaml 文件:

  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. name: nginx-deployment
  5. labels:
  6. app: nginx
  7. spec:
  8. replicas: 2
  9. selector:
  10. matchLabels:
  11. app: nginx
  12. template:
  13. metadata:
  14. labels:
  15. app: nginx
  16. spec:
  17. containers:
  18. - name: nginx
  19. image: nginx:1.18.0

应用 nginx-deployment.yaml 文件:

  1. $ kubectl apply -f nginx-deployment.yaml
  2. deployment.apps/nginx-deployment created

查看运行状态

查看 Pod 运行情况:

  1. $ kubectl get pods
  2. NAME READY STATUS RESTARTS AGE
  3. nginx-deployment-9fbc65d67-9j68x 1/1 Running 0 1m
  4. nginx-deployment-9fbc65d67-nwbhj 1/1 Running 0 1m

查看 Deployment 部署情况:

  1. $ kubectl get deployment
  2. NAME READY UP-TO-DATE AVAILABLE AGE
  3. nginx-deployment 2/2 2 2 29m

我们也可以通过 describe 命令进行查看

  1. $ kubectl describe pod nginx-deployment-9fbc65d67-9j68x
  2. Name: nginx-deployment-9fbc65d67-9j68x
  3. Namespace: default
  4. Priority: 0
  5. Node: docker-desktop/192.168.65.3
  6. Start Time: Fri, 01 May 2020 17:36:12 +0800
  7. Labels: app=nginx
  8. pod-template-hash=9fbc65d67
  9. ...
  10. Events:
  11. Type Reason Age From Message
  12. ---- ------ ---- ---- -------
  13. Normal Scheduled 45m default-scheduler Successfully assigned default/nginx-deployment-9fbc65d67-9j68x to docker-desktop
  14. Normal Pulling 45m kubelet, docker-desktop Pulling image "nginx:1.18.0"
  15. Normal Pulled 44m kubelet, docker-desktop Successfully pulled image "nginx:1.18.0"
  16. Normal Created 44m kubelet, docker-desktop Created container nginx
  17. Normal Started 44m kubelet, docker-desktop Started container nginx

查看 Dashboard

在应用了 Nginx 的 Deployment 后,我们可以查看上一章节中我们所搭建的 Dashboard:

image

可能你在想,我只是执行了一条命令,怎么就把 Nginx 跑起来了,这时候你可以去查看容器组中的事件,就能够看到这个容器在运行时做涉及到的事件:

image

部署 Nginx

创建 Nginx Service

  1. apiVersion: v1
  2. kind: Service
  3. metadata:
  4. name: nginx-service
  5. labels:
  6. app: nginx
  7. spec:
  8. selector:
  9. app: nginx
  10. ports:
  11. - name: nginx-port
  12. protocol: TCP
  13. port: 80

应用 nginx-service.yaml 文件:

  1. $ kubectl apply -f nginx-service.yaml

查看应用的运行情况:

  1. $ kubectl get services -o wide

但这时候是无法访问到 Nginx 的,我们可以通过 Kubernetes 的 NodePort 的方式对外提供访问:

  1. apiVersion: v1
  2. kind: Service
  3. metadata:
  4. name: nginx-service
  5. labels:
  6. app: nginx
  7. spec:
  8. selector:
  9. app: nginx
  10. ports:
  11. - name: nginx-port
  12. protocol: TCP
  13. port: 80
  14. nodePort: 30001
  15. targetPort: 80
  16. type: NodePort

然后再进行访问:

  1. $ curl http://127.0.0.1:30001
  2. <!DOCTYPE html>
  3. <html>
  4. <head>
  5. <title>Welcome to nginx!</title>
  6. ...

至此我们已经打通了和 Nginx 之间的访问。

部署 Go 程序

在部署环境中常常需要将应用程序部署上去,然后对外进行提供服务,我们模拟一个 Go 程序:

  1. func main() {
  2. r := gin.Default()
  3. r.GET("/ping", func(c *gin.Context) {
  4. c.String(http.StatusOK, "pong")
  5. })
  6. err := r.Run(":9001")
  7. if err != nil {
  8. log.Fatalf("r.Run err: %v", err)
  9. }
  10. }

编写和编译 Dockerfile

在项目根目录创建 Dockerfile 文件,进行编写:

  1. FROM golang:latest
  2. ENV GOPROXY https://goproxy.cn,direct
  3. WORKDIR $GOPATH/src/github.com/eddycjy/awesome-project
  4. COPY . $GOPATH/src/github.com/eddycjy/awesome-project
  5. RUN go build .
  6. EXPOSE 8000
  7. ENTRYPOINT ["./awesome-project"]

编译并打标签:

  1. $ docker build -t eddycjy/awesome-project:v0.0.1 .
  2. ...
  3. Successfully built b53cef4d2967
  4. Successfully tagged eddycjy/awesome-project:v0.0.1

验证打包进 Docker 中的程序是否正常运行:

  1. $ docker run -p 10001:9001 awesome-project
  2. [GIN-debug] GET /ping --> main.main.func1 (3 handlers)
  3. [GIN-debug] Listening and serving HTTP on :9001
  4. [GIN] 2020/05/03 - 01:51:40 | 200 | 16.9µs | 172.17.0.1 | GET "/ping"

上传到 Dockerhub

登陆并推送镜像到 Dockerhub:

  1. $ docker login
  2. $ docker push eddycjy/awesome-project:v0.0.1
  3. The push refers to repository [docker.io/eddycjy/awesome-project]
  4. 8192ac09ffeb: Pushed
  5. 9eb17b90d619: Pushed
  6. b04d698ea69d: Pushed
  7. 31561785c3fc: Mounted from library/golang
  8. 4486631650dc: Mounted from library/golang
  9. 5e28718a7d23: Mounted from library/golang
  10. ea1227feeccb: Mounted from library/golang
  11. 9cae1895156d: Mounted from library/golang
  12. 52dba9daa22c: Mounted from library/golang
  13. 78c1b9419976: Mounted from library/golang
  14. v0.0.1: digest: sha256:a1ef61e899db75eb2171652356be15559f1991b94a971306fb79ceccea8dd515 size: 2422

这时候你在 hub.docker.com 上就能看的你刚刚所上传的镜像内容:

image

编写 Kubernetes 配置

接下来我们需要针对刚刚所打包的 Go 程序创建 Deployment,编写 go-deployment.yaml 文件:

  1. apiVersion: extensions/v1beta1
  2. kind: Deployment
  3. metadata:
  4. name: awesome-project
  5. labels:
  6. app: awesome-project
  7. spec:
  8. replicas: 2
  9. selector:
  10. matchLabels:
  11. app: awesome-project
  12. template:
  13. metadata:
  14. labels:
  15. app: awesome-project
  16. spec:
  17. containers:
  18. - name: awesome-project
  19. image: eddycjy/awesome-project:v0.0.1

创建 Service,编写 go-service.yaml:

  1. apiVersion: v1
  2. kind: Service
  3. metadata:
  4. name: awesome-project-svc
  5. labels:
  6. app: awesome-project
  7. spec:
  8. ports:
  9. - port: 9001
  10. type: ClusterIP
  11. selector:
  12. app: awesome-project

部署 Ingress

Ingress Controller

我们采用 Docker for Mac 特定提供的 Ingress Controller 部署脚本:

  1. $ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-0.32.0/deploy/static/provider/cloud/deploy.yaml

其会所有命名空间监视 Ingress 对象,并配置 RBAC 权限,否则你有可能会遇到 403 Forbidden 的问题。

Nginx Ingress

在完成了 Ingress Controller 等相关部署后,我们可以正式的部署属于自己业务的 Nginx Ingress 对象:

  1. apiVersion: extensions/v1beta1
  2. kind: Ingress
  3. metadata:
  4. name: test-ingress
  5. annotations:
  6. nginx.ingress.kubernetes.io/use-regex: "true"
  7. spec:
  8. rules:
  9. - host: website-ingress.local
  10. http:
  11. paths:
  12. - backend:
  13. serviceName: awesome-project-svc
  14. servicePort: 9001

kubectl apply -f 应用刚刚所编写的配置文件,然后查看运行情况:

  1. $ kubectl get ingresses.
  2. NAME HOSTS ADDRESS PORTS AGE
  3. test-ingress website-ingress.local localhost 80 8h

如何发现 ADDRESS 为空,则存在问题,需要进行排查(可能性有很多)。在确定 ADDRESS 属性正常后,我们需要打开 /etc/hosts 并配置 HOST 127.0.0.1 awesome-project.local ,并进行验证:

  1. $ curl http://awesome-project.local/ping
  2. pong

至此,我们完成了一个简单的 Go 程序的部署和外部调用。

小结

在本章中,我们通过部署 Nginx、Ingress、Go 程序的方式,直接实践了 Kubernetes 的基本流程,达到了将自己的简单程序部署在 Kubernetes 的一个小目标,接下来在后续的章节中我们将进一步针对文中所使用到的相关属性和内容进行详细说明。

毕竟在实践过后,就要去了解为什么,这样子才能做到融会贯通。