laravel+k8s+gitlab+ci/cd全流程

我司项目现在跑在阿里云的ACK上,用到的语言有php(主力语言)、golang、python、c#,一共跑了十来个微服务,扛过了好几次的大流量,目前生产环境也稳定运行了两年多了。最近因为要离职了,所以完整地回顾一下整个流程,后面有可能还会更新其他的一些东西,权当是做个记录吧~

更新日志

  • 2022-09-23 init

前期准备

  • gitlab:用于代码仓库和CI/CD
  • 阿里云ACK:托管版的kubernetes(1.22.10)
  • 阿里云镜像仓库:用于托管镜像

开始

先定义项目名称为 myapp,所有用户名都为 sellmoe

创建镜像仓库

在阿里云容器镜像服务中,创建一个仓库 myapp_basemyapp,类型都设为私有

构建基础镜像

  • 为了避免后面ci/cd中update和安装扩展带来的时间浪费,所以做一个基于php8.0的基础镜像很有必要,如果还有其他项目,完全可以复用
  • 首先咱们用命令在本地拉取laravel的代码 laravel new myapp
  • 在根目录下新建一个 Dockerfile_Base 文件,构建一个基础镜像
FROM php:8.0-fpm
MAINTAINER sellmoe

RUN apt-get update
RUN apt-get install -y libmcrypt-dev libonig-dev zlib1g-dev libpng-dev libzip-dev zip && pecl install mcrypt-1.0.4
RUN docker-php-ext-enable mcrypt \
    && docker-php-ext-install \
        pdo \
        pdo_mysql \
        mbstring \
        pcntl \
        opcache \
        bcmath \
        gd \
        zip

RUN cp /usr/local/etc/php/php.ini-production /usr/local/etc/php/php.ini
RUN sed -i 's/disable_functions =/disable_functions = passthru,exec,system,chroot,chgrp,chown,shell_exec,popen,ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru/' /usr/local/etc/php/php.ini
RUN sed -i 's/;date.timezone =/date.timezone = PRC/' /usr/local/etc/php/php.ini
RUN sed -i 's/;opcache.enable=1/opcache.enable=1/' /usr/local/etc/php/php.ini

RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer

然后用 docker build -f Dockerfile_Base -t registry.cn-hongkong.aliyuncs.com/sellmoe/myapp_base:release . 构建好基础镜像

最后推送到容器镜像仓库 docker push registry.cn-hongkong.aliyuncs.com/sellmoe/myapp_base:release

构建主项目镜像

还是laravel根目录新建Dockerfile,以基础镜像为基础,把代码拷贝进去

FROM registry.cn-hongkong.aliyuncs.com/sellmoe/myapp_base:release
MAINTAINER sellmoe

COPY ./ /var/www/html/

EXPOSE 9000

k8s部署文件

一般k8s部署的文件都得新开一个git项目,我们把所有的相关yaml文件全部放到这个项目中

ConfigMap: laravel的.env

新建一个configmap-laravel.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: cvs-config
data:
  .env: |
    APP_NAME=MyApp
    APP_ENV=production
    ...

ConfigMap: nginx配置文件

新建一个configmap-nginx.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  site.conf: |
    server {
        listen    80;
        server_name myapp.test;

        location / {
            try_files uriuri/ /index.php?args;
        }

        location ~ \.php {
            root             /var/www/html/public;
            fastcgi_pass     php:9000;
            fastcgi_index    index.php;
            include          fastcgi_params;
            fastcgi_param    SCRIPT_FILENAME  $document_root/index.php;
        }
        error_log  /var/log/nginx/error.log;
        access_log /var/log/nginx/access.log;
    }

Deployment: nginx

新建一个deployment-nginx.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  labels:
    tier: backend
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
      tier: backend
  template:
    metadata:
      name: nginx
      labels:
        app: nginx
        tier: backend
    spec:
      containers:
        - name: nginx
          image: nginx:latest
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 80
              protocol: TCP
              name: http
          livenessProbe:
            initialDelaySeconds: 15
            periodSeconds: 15
            tcpSocket:
              port: 80
            timeoutSeconds: 30
          readinessProbe:
            initialDelaySeconds: 15
            periodSeconds: 30
            tcpSocket:
              port: 80
          volumeMounts:
            - mountPath: /etc/nginx/conf.d/
              name: nginx-config
              readOnly: true
      volumes:
        - name: nginx-config
          configMap:
            defaultMode: 420
            name: nginx-config

Deployment: php

新建一个deployment-php.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: php
  labels:
    tier: backend
spec:
  replicas: 1
  minReadySeconds: 3 #Pod就绪/可用后的时间
  revisionHistoryLimit: 6 #保留的旧副本数量,方便回滚到上一个版本:kubectl rollout undo deployment.v1.apps/DEPLOY_NAME
  strategy: #滚动更新策略,Recreate:先杀Pods,再创建;RollingUpdate:滚动更新
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1 #最大峰值,可是绝对值或百分比(默认25%),用来指定可以创建的超出期望 Pod 个数的 Pod 数量。比如30%表示新旧pod数量不超过130%
      maxUnavailable: 50% #更新中不可用Pod的个数上限,可是绝对值或百分比(默认25%)
  selector:
    matchLabels:
      app: php #与下面template中对应
      tier: backend
  template:
    metadata:
      name: php
      labels:
        app: php
        tier: backend
    spec:
      #affinity: #亲和性
      #  podAntiAffinity: #podAffinity:pod亲和性,podAntiAffinity:pod反亲和性
      #    preferredDuringSchedulingIgnoredDuringExecution: #软策略:最好满足,与之相对的赢策略requiredDuringSchedulingIgnoredDuringExecution表示一定满足
      #      - podAffinityTerm: #匹配策略
      #          labelSelector:
      #            matchExpressions:
      #              - key: app
      #                operator: In
      #                values:
      #                  - backend
      #          topologyKey: kubernetes.io/hostname
      #        weight: 100
      initContainers: #初始化容器,在所有pod前运行,用于运行镜像中不存在的工具和脚本。kubelet会一直尝试运行直到成功,如果pod的restartPolicy是Never,那么只尝试一次,会标记pod失败
        - name: artisan #初始化容器名,可通过kubectl logs POD_NAME -c init容器名查看日志
          image: registry.cn-hongkong.aliyuncs.com/sellmoe/myapp:release
          imagePullPolicy: Always
          envFrom: #.env文件先挂载,直接可以拷贝到共享volume中,下面的就不需要挂载了
            - configMapRef:
                name: cvs-config
          args:
            - /bin/bash
            - -c
            - (php artisan migrate || true) && (php artisan config:cache || true) && (php
              artisan route:cache || true) && (cp -rp /var/www/html /codebase)
          volumeMounts: #init容器先把代码拷贝到共享volume中
            - mountPath: /codebase
              name: codebase
      containers:
        - name: php
          image: registry.cn-hongkong.aliyuncs.com/sellmoe/myapp:release
          imagePullPolicy: Always
          ports: #暴露的端口
            - containerPort: 9000
              protocol: TCP
          livenessProbe: #存活探测器
            failureThreshold: 3
            initialDelaySeconds: 15 #第一次探测前延迟的秒数
            periodSeconds: 10 #每次探测间隔秒数
            successThreshold: 1
            tcpSocket: #表示用tcp套接字来检测存活状态
              port: 9000
            timeoutSeconds: 1
          readinessProbe: #就绪探测器
            failureThreshold: 3
            initialDelaySeconds: 15
            periodSeconds: 5
            successThreshold: 1
            tcpSocket:
              port: 9000
            timeoutSeconds: 1
          resources: #资源限制
            limits:
              cpu: 200m
              memory: 400M
            requests:
              cpu: 100m
              memory: 200M
          volumeMounts:
            - mountPath: /var/www/
              name: codebase
          lifecycle:
            postStart:
              exec:
                command: [ "/bin/sh", "-c", "chmod 777 -R storage && chmod 777 -R bootstrap/cache" ]

      volumes: #共享代码volume(app和initContainer)
        - name: codebase
          emptyDir: {}
      imagePullSecrets:
        - name: regsecret #拉取镜像的secret

Service: nginx

新建一个文件service-nginx.yaml

apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    tier: backend
spec:
  selector:
    app: nginx
    tier: backend
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

Service: php

新建一个service-php.yaml

apiVersion: v1
kind: Service
metadata:
  name: php
  labels:
    tier: backend
spec:
  selector:
    app: php
    tier: backend
  ports:
    - port: 9000
      protocol: TCP

gitlab配置

因为私有gitlab拉取私有仓库的镜像是需要认证的,所以我们先获取阿里云拉取docker镜像的auth

echo -n "阿里云用户名:阿里云密码" | base64

然后到gitlab对应项目中,把下面这段配置到CI/CD的variables中,key可以是ALIYUN_AUTH_CONFIG

{
    "auths": {
        "仓库地址,如:registry.cn-hongkong.aliyuncs.com": {
            "auth": "上一步生成的auth config"
        }
    }
}

.gitlab-ci.yaml

在项目根目录下新建 .gitlab-ci.yaml 文件

stages:
  - deploy

deploy:
  stage: deploy
  image: docker:dind #docker in docker
  tags:
    - docker
  only:
    - master
  script:
    - mkdir ~/.docker
    - echo ${ALIYUN_AUTH_CONFIG} > ~/.docker/config.json
    - docker build -f Dockerfile -t registry.cn-hongkong.aliyuncs.com/sellmoe/myapp:release .
    - docker push registry.cn-hongkong.aliyuncs.com/sellmoe/myapp:release

配置推送镜像自动触发重新部署

因为我们推送了镜像,但是并没有让k8s滚动更新,所以在阿里云容器服务控制台选择无状态 - php触发器,创建一个重新部署的触发器,然后把触发器链接复制到容器镜像服务对应镜像仓库的触发器中

helm chart

这篇文章还没有评论

发表评论

*

List
Love
00:00