从零创建一个 Kubernetes Web 应用

前言

从如何创建一个PHP Web应用入手,带大家进入Kubernetes的世界。

基础

环境

  • CentOS 7.5 (Kernel 3.10)
  • Minikube (Kubernetes 1.10.0)

对你的要求

我假设你已经掌握了下面的基础技能:

  • Docker && 会写Dockerfile
  • 如何Google
  • 拥有一个DockerHub账号
  • 手动编译过LNMP或者LAMP

构建基础镜像

alt

上图描述了我们需要创建的Containers,其中Pause ContainerKubernetes自带的所以我们不用关心,但是十分重要,未来将会有一篇文章来描述Pause Container到底干什么的。
其实基础镜像一般用官方现成的就行了,但是在学习过程中建议还是手动编译一下,了解下官方默认配置有哪些坑。Dockerfile代码我会放到GitHub上, 因为在这里展示实在是太长了。

创建Nginx镜像

Nginx: Nginx For K8S GitHub Repo

编译Nginx镜像

    docker build . -t motecshine/nginx1.12-for-k8s:v0.1.0
    docker push motecshine/nginx1.12-for-k8s:v0.1.0

创建PHP-FPM镜像

FPM: FPM For K8S GitHub Repo

编译FPM镜像

    docker build . -t motecshine/php71-for-k8s:v0.1.0
    docker push motecshine/php71-for-k8s:v0.1.0

注意事项: Dockerfile CMD 需要关闭NginxFPMdaemon特性,具体看我REPO的Dockerfile, 这样是为了保证Container生命周期与POD生命周期一致。

构建业务镜像

我们将基于上述镜像来创建我们的业务镜像.

创建Code镜像

我们基于Laravel来创建镜像。

Code: Code For K8S GitHub Repo

编译Code镜像

    docker build . -t motecshine/code-for-k8s:v0.1.1
    docker push motecshine/code-for-k8s:v0.1.1

创建Nginx镜像

laravel-nginx-for-k8s: Laravel For K8S GitHub Repo

编译Nginx镜像

    docker build . -t  motecshine/laravel-nginx-for-k8s:v0.1.1
    docker push  motecshine/laravel-nginx-for-k8s:v0.1.1

创建PHP-FPM镜像

laravel-fpm-for-k8s: Laravel-FPM For K8S GitHub Repo

编译FPM镜像

    docker build . -t  motecshine/laravel-fpm-for-k8s:v0.1.0
    docker push  motecshine/laravel-fpm-for-k8s:v0.1.0

构建Kubernetes应用

整体架构

整体架构如上图所示

构建最小化运行单元(Pod)

alt

创建Deployment

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: laravel
  namespace: default
spec:
  replicas: 1 # 期待副本数量
  template:
    metadata:
      labels:
        app: laravel # app label
        version: testing
    spec:
      containers:
      - name: code
        image: motecshine/code-for-k8s:v0.1.1
        volumeMounts: # 挂载目录
        - mountPath: /data2
          name: code
      - name: fpm
        image: motecshine/laravel-fpm-for-k8s:v0.1.0
        imagePullPolicy: IfNotPresent
        resources: # 资源限制
           limits:
             cpu: 350m
             memory: 350Mi
           requests:
             cpu: 50m
             memory: 50Mi
        ports:
        - name: fpm
          containerPort: 9000
        volumeMounts:
        - mountPath: /data/code # 挂载code
          name: code
        - mountPath: /var/log # 挂载日志
          name: log  
      - name: laravel-nginx
        image: motecshine/laravel-nginx-for-k8s:v0.1.0
        imagePullPolicy: IfNotPresent
        resources:
          limits:
            cpu: 350m
            memory: 350Mi
          requests:
            cpu: 50m
            memory: 50Mi
        ports:
        - name: ivp-nginx
          containerPort: 80 # 暴露Endpoint
        volumeMounts:
        - mountPath: /data/code
          name: code
        - mountPath: /var/log
          name: log  
      volumes:
      - name: code
        emptyDir: {}
      - name: log
        hostPath:
          path: /var/log
          type: Directory

构建Service

apiVersion: v1
kind: Service
metadata:
  name: laravel-service
  namespace: default
  labels:
    app: laravel-service
    version: testing-service
spec:
  type: ClusterIP
  selector:
    app: laravel
    version: testing
  ports:
    - name: http
      port: 80

构建Ingress


apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: laravel-ingress
  namespace: default
  labels:
    app: laravel-ingress
spec:
  rules:
  - host: laravel.test
    http:
      paths:
      - path: /
        backend:
          serviceName: laravel-service
          servicePort: 80

安装Minikube

curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 && chmod +x minikube && sudo cp minikube /usr/local/bin/ && rm minikube

安装Traefik

我们使用开源的Ingress组件安装参考这里

启动Web应用

上面的配置文件在这里

git clone git@github.com:motecshine/laravel-k8s-config.git
cd laravel-k8s-config && kubectl create -f .

效果

效果

结语

简单的介绍了如何创建一个Web应用,这仅仅是个开始,Kubernetes背后是一个庞大的生态环境, CI,CD,ELK(EFK), APM,让我们一点点揭开它神秘的面纱。

下一篇将Kubenetes基于EFK日志收集平台。

本作品采用《CC 协议》,转载必须注明作者和本文链接
本帖由系统于 5年前 自动加精
讨论数量: 17

爱你哦,猪哥 :kissing_heart:

5年前 评论

@郑方方 晚上翻你牌子

5年前 评论
Destiny

爱你哦,猪哥 :kiss: :kiss: :kiss:

5年前 评论

太优秀了啊啊啊啊啊啊啊 = 啊=

5年前 评论

优秀哦 :+1:

5年前 评论

猪哥太优秀了啊

5年前 评论

请问 你用 Traefik,是如何把 80端口 暴漏出来的?

5年前 评论

@klgd Traefik->Service->Pod ContainerPort, Traefik 作为L7层的代理,就想Nginx一样启动默认80 和 443端口

5年前 评论

@Noober Phper 可能是我没说清楚,集群外访问的话,如果ingress前面没有lb,就需要ingress controller自身暴漏NodePort,默认service NodePort范围是30000-32767,你是如何把80端口暴漏出来的?修改NodePort范围吗?会不会对node节点有影响?

5年前 评论

@klgd

想暴露k8s Service 服务到互联网大概有三种方式:

  1. NodePort(手动映射 Service Endpoint 到 VM Port)
  2. ClusterIP(kube-proxy 通过iptables rules 转发)
  3. Loadbalance(Traefik Nginx-ingress-controller)

你应该说的是第一种,第一种的安全性与可维护性都很差, 服务一多起来,服务器防火墙就成了窟窿,很少会用第一种。第二种也很少见。

5年前 评论

@Noober Phper Ingress 就是用反向代理负载均衡器将 k8s 集群内的Service暴露到集群外,而Ingress自身部署其实也是一个Service,那么这个Service你是如何暴漏到集群外的?NodePort还是LoadBlancer?

5年前 评论

老铁,图片挂了

4年前 评论
黑将军

大哥,图片都挂了

4年前 评论

emptyDir 目录下文件没有了吧,容器间共享不了

3年前 评论

@testdrive hack的代码在这里 这篇文章块两年了,其实这不是最佳实践,当初写的目的只是为了给自己梳理思路。 我觉得更好的方式有两种:

  1. code container as init container ,解压到Volume里,共享代码。
  2. 使用Rook这里的Storage CRD Operator,来去除存储状态。

如果你有更好的方式也可以告诉我

3年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!