项目容器化改造心得

概述

背景

近来和同事共同开发的迁移平台项目想进行容器化改造,顺应大趋势往容器化这边靠,项目前端平台利用Django开发,后端Restful API利用高性能Web框架Tornado完成,Agent端利用Flask开发,各取了几个大Python框架的优势。

之前CI/CD测试环境用的是GitLab CI,Master提交merge request后自动构建部署,正式环境通过Jenkins Pipeline手动拉去release部署,容器化改造将Jenkins托管在Kubernetes之上,Master接受Job请求,动态生成slave来完成Job任务。

此文记录了容器化改造中自己遇到的一些心得,可能自己研究的还不够,以下均为个人理解,大佬不喜勿喷,在本次利用Kubernetes将项目容器化过程中,决定Python项目有点大材小用,但是通过这次改造,理解了不少容器化的特征,不断的提升自己IT技术,丰富自己的技能栈。 如果你想和更多Kubernetes技术专家交流,可以加我微信liyingjiese,备注『加群』。群里每周都有全球各大公司的最佳实践以及行业最新动态

容器化改造优势

  • 更省:极大的资源利用效率, 最大限度榨取和共享物理资源,多项目更能体现出容器化多优势,节约部署IT成本。
  • 更快:秒级启动,实现业务系统更快的开发迭代和交付部署。
  • 弹性:可根据业务负载进行弹性容器伸缩,弹性扩展。
  • 方便:容器化业务部署支持蓝绿/灰度/金丝雀等发布,回滚,更加灵活方便。
  • 灵活:监控底层Node节点健康状态,灵活调度至最优节点部署。
  • 强一致性:容器将环境和代码打包在镜像内,保证了测试与生产环境的强一致性。

容器化改造的要求

  • 开发人员熟悉Docker虚拟化技术,熟练编写Dockerfile。
  • 熟悉Kubernetes容器化编排系统, 熟悉各组件资源清单编写。
  • 开发需要考虑后期容器编排部署的需求来组织结构和编写代码。
  • 部署人员需要熟悉Kubernetes资源清单各参数含义,需要总体把控架构中到从上到下架构。
  • 考虑高可用架构和rbac安全策略,外部流量引入及后期扩容伸缩。

工具

云原生生态

一入云原生深似海,下图为我们更好的全局性了解云原生生态。

工具应用

本次项目改造用到的一些工具和应用与大家分享(后期有时间将各个工具应用单独写出来分享)。

  • 代码托管:GitLab服务器进行代码托管,及GitLab CI/CD,后期可以将其托管至Kubernetes集群之上。
  • 私有镜像托管:利用Harbor进行镜像存储,审计管理及镜像检查,后期可托管至Kubernetes之上。
  • 集群管理:
    • kubernetes-dashboard部署,Web界面方便各组件查看管理,简单容器Terminal管理,日志分享查看。
    • Rancher部署,导入私有化Kubernetes平台,方便集群管理及app安装部署。
  • 存储管理:
    • Ceph到mgr分布式集群Web界面管理。
    • minio/chartmuseum对象存储,方便chart存储管理。
  • 集成发布:Jenkins进行持续集成,持续发布,后期可以将其托管至Kubernetes集群之上。
  • 日志监控:EFK进行Kubernetes集群容器日志监控管理,F为Flutend容器化监控利器。
  • Helm仓库管理:KubeApps进行Chart,Registry添加,方便Helm安装部署。
  • 容器内APP监控:Prometheus + Grafana,各个APP内进行export出来,进行单个APP到matric监控。
  • 下图为导航页,直观的展示用的这些工具

改造的要求

程序要求

项目结构

将配置文件单独创建config文件夹,方便后期Kubernetes创建ConfigMap进行资源映射。

如果后期部署为deployment无状态应用,应该将共享的数据存储单独创建目录,方便后去volume挂载。

项目结果目录下单独创建deploy目录存放。

例如次项目,分为创建configmap/deployment/service已经拉去私有仓库代码的Secret。

项目下均适用entrypoint.sh为容器入口,最后添加exec “$@”,方便后期添加配置扩展。

代码要求

配置文件尽可能使用yaml语言编写,方便后期加载为ConfigMap中便于修改读写。

由于后期方便容器监控,采用Fluentd配合EL进行集群及应用监控,监控容器目录为/var/lib/docker/containers/*.log,需要将日志输出到stdout,所以对于需要监控到日志,可以定向到标准输出/标准错误输出已经日志文件内。

架构要求

基础资源

  • 计算,利用云服务器搭建部署Kubernetes集群,提供计算与内存资源。
  • 存储,需要利用云服务器磁盘部署Ceph分布式存储系统,为Kubernetes提供底层存储资源。
  • 网络,前段需要LB,为应用代理到NodePort,Kubernetes集群内部使用Flannel网络,Node到Node之前通过VPC私有网络通讯。
    • 容器间通信:同一个Pod内多个容器间的通信,使用lo网卡通信
    • Pod间通信:Pod IP直接与Pod IP通信
    • Pod与Service:Pod IP直接与Cluster IP
    • Service与集群外部客户端的通信,Ingress、NodePort、Loadbacer

流量引入

需要结合部署在公有化/私有化,还是裸机上,需要提前规划好前段时云LB就可以借助其部署证书,七层加载证书。

如果没有云产品就需要考虑Ingress流量引入集群加载证书。

项目部分示例

存储类

利用Ceph集群,构建存储类,同时利用CephFS来解决跨Node挂载的应用。

存储类ceph-storageclass.yaml:

apiVersion: storage.k8s.io/v1

kind: StorageClass

metadata:

name: ceph-rdb

provisioner: ceph.com/rbd

reclaimPolicy: Retain

parameters:

monitors: 10.xx.xx.xx:6789

pool: kube

adminId: admin

adminSecretName: ceph-admin-secret

adminSecretNamespace: kube-system

userId: kube

userSecretName: ceph-client-secret

userSecretNamespace: kube-system

fsType: xfs

imageFormat: "2"

imageFeatures: "layering"

Ceph认证ceph-secret.yaml:

apiVersion: v1

kind: Secret

metadata:

name: ceph-admin-secret

namespace: kube-system

type: "kubernetes.io/rbd"

data:

# ceph auth get-key client.admin |base64

key: QVFCRitmUmM1c1FxxxxxxxxxxxxxxxxxxxxxxxxHFoQVh6NlRvQ2c9PQ==

对于共享目录:

apiVersion: v1

kind: PersistentVolumeClaim

metadata:

name: go2cloud-api-pvc

namespace: default

spec:

storageClassName: "ceph-rdb"

accessModes:

- ReadWriteOnce

resources:

requests:

  storage: 8Gi

配置文件通过ConfigMap挂载:

apiVersion: v1

data:

config.yaml: |

---

DB_ENGINE: mysql

DB_HOST: mariadb-cluster-mariadb-master.default.svc.cluster.local

DB_PORT: 3306

DB_USER: go2clouduser

DB_PASSWORD: go2xxxxxxxxx

DB_NAME: go2cxxxxxxxx



# Use Redis as cache

# Redis配置,连接replication的master节点

REDIS_HOST: redis-cluster-redis-ha-announce-0.default.svc.cluster.local

REDIS_PORT: 6379

REDIS_PASSWORD: go2cloxxxxxxxx

# go2cloud-platform 监听端口

HTTP_LISTEN_PORT: 8088

# callback url

API_MIGRATE_SERVER_URL: http://go2cloud-api-service.default.svc.cluster.local:8004

PLATFORM_CALLBACK_URL: http://go2cloud-platform-service.default.svc.cluster.local:8088

kind: ConfigMap

metadata:

name: go2cloud-platform-cm

应用相关资源

go2cloud-platform-deployment.yaml:

apiVersion: apps/v1

kind: Deployment

metadata:

name: go2cloud-platform

namespace: default

spec:

selector:

matchLabels:

  # 匹配下面选择的template 中的label.app名称

  app: go2cloud-platform

replicas: 2

template:

metadata:

  labels: 

    app: go2cloud-platform

    release: latest

spec: 

  imagePullSecrets:

  - name: registry-secret

  containers:

  - name: go2cloud-platform

    image: 10.234.xxx.xxx/go2cloud/go2cloud-plaxxxxx:latest

    imagePullPolicy: IfNotPresent

    ports:

    - containerPort: 8088

      protocol: TCP

    volumeMounts:

      # 必须匹配volumes的名称

    - name: go2cloud-platform-config

      mountPath: /data/config

      readOnly: true

    resources:

      requests:

        cpu: 250m

        memory: 520Mi

      limits:

        cpu: 500m

        memory: 1024Mi

    livenessProbe:

      tcpSocket: 

        port: 8088

      initialDelaySeconds: 20

  volumes:

  # 定义逻辑卷的名称

  - name: go2cloud-platform-config

    configMap:

      # 使用configmap资源的名称

      name: go2cloud-platform-cm

      items:

      # 使用configmap中到那个key

      - key: config.yaml

        # 使用configmap中到key映射到容器中到文件名称

        path: config.yaml

        mode: 0644 

go2cloud-platform-service.yaml:

apiVersion: v1

kind: Service

metadata:

name: go2cloud-platform-service

namespace: default

spec:

selector:

app: go2cloud-platform

type: NodePort

ports:

- name: http

nodePort: 30020

port: 8088

targetPort: 8088

protocol: TCP

registry-secret.yaml:

apiVersion: v1

kind: Secret

metadata:

name: registry-secret

type: kubernetes.io/dockerconfigjson

data:

.dockerconfigjson: ewoJImF1dGhzIjogewoJCSIxMC4yMzQuMi4yMTgiOiB7CgkJCSJhdXRoIjogIllXNWphRzVsZERwWWVIcDRRRGM0T1E9PSIKCQl9Cgl9LAoJIkh0dHBIZWFkZXJzIjogewoJCSJVc2Vyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Dockerfile:

FROM python:latest

LABEL maintainer="kaliarch"

ENV BASE_ROOT="/data" 

ADD . ${BASE_ROOT}

RUN pip install --default-timeout=100 -r ${BASE_ROOT}/requirements/requirements.txt \

&& ln -s ${BASE_ROOT}/entrypoint.sh /bin/entrypoint.sh





EXPOSE 8088/tcp

ENTRYPOINT ["/bin/sh","/bin/entrypoint.sh"]

CMD ["python","/data/runserver","start","all"]

entrypoint.sh:

#!/bin/sh

# config go2cloud-api configfile





exec "$@"

反思

  • 个人决定云原生后期会成为大趋势,提前掌握容器化编排技术,不至于技术栈落伍。
  • 充分利用云生态应用切合自身项目特点进行容器化改造会快速不少。
  • 觉得云原生是将来的大趋势,尽快入门,拥抱云原生。

原文链接: https://juejin.im/post/5d0f90646fb9a07eb3098580