61

项目容器化改造心得

 4 years ago
source link: https://www.tuicool.com/articles/2iyYvur
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

概述

背景

近来和同事共同开发的迁移平台项目想进行容器化改造,顺应大趋势往容器化这边靠,项目前端平台利用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安全策略,外部流量引入及后期扩容伸缩。

工具

云原生生态

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

aa10e2ab676c956920a4ce805dc55323.png

工具应用

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

  • 代码托管: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监控。
  • 下图为导航页,直观的展示用的这些工具
    2fd7e571be92bb9fe71b942a5b2a119b.png

改造的要求

程序要求

项目结构

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

fe94dd58022720b22531ab8b8f749919.png

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

d322ce4450ce82e01c0e2a3f7d4dff29.png

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

b88b9dc96602c8967e385cf809d4159d.png

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

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

b88b8d006bb7063c73623fbadb84f8f0.png

代码要求

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

95c0dfcfd14cb7c22719543958ac9740.png

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

47e2e72812a1a279856c60b9192b7f93.png

架构要求

基础资源

  • 计算,利用云服务器搭建部署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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK