写点什么

使用 Kubernetes 部署应用

作者:Rayzh
  • 2021 年 12 月 30 日
  • 本文字数:3681 字

    阅读完需:约 12 分钟

使用Kubernetes部署应用

不同语言开发的应用在制作 Docker 镜像的方法是不同的。对 Go 和 Java 来说,容器化改造是比较有友好的;但是对于 PHP、Python 这类脚本语言,就稍微有点复杂了。这里举的两个例子是 PHP 和 Python 的 HTTP 服务。

一、Nginx+PHP 提供 WEB 服务

​ LNMP 架构是非常常用的一种 webservice。这里的场景是使用 PHP 的 yaf 框架开发的应用进行容器化的改造。

​ 按照以往的部署方式,我们是需要在一台或者多台服务器上部署 Nginx 和 PHP 两个服务。PHP 服务上,我们要根据需要安装 yaf 框架和一些 PHP 的拓展如 mysql、mongodb、redis 等;Nginx 服务则配置一些静态资源的信息和将动态请求转到 PHP 的默认 9000 端口处理。如果是这样的话,我们就相当于提交了两个镜像,使用 docker-compose 可以快速部署,但是在 Kubernetes 上就显得有点不合适。

1-1 基础镜像编译

​ 经过一段时间的尝试,我们使用了 supervisor 这个进程管理工具,将 nginx 和 php-fpm 编译到一个镜像中。


Dockerfile


FROM php:7.2-fpm
# nginxRUN apt-get -o Acquire::Check-Valid-Until=false update && apt install -y build-essential zlib1g-dev libpcre3 libpcre3-dev libssl-dev libxslt1-dev libxml2-dev libgeoip-dev opensslRUN curl -L -o /tmp/nginx-1.18.0.tar.gz http://nginx.org/download/nginx-1.18.0.tar.gz \ && tar xfz /tmp/nginx-1.18.0.tar.gz -C /tmp \ && cd /tmp/nginx-1.18.0 \ && ./configure --prefix=/usr/local/nginx --with-http_ssl_module \ && make && make install \ && rm -rf /tmp/nginx-1.18.0COPY nginx.conf /usr/local/nginx/conf/nginx.conf
# PHP extensions
# phpredis 3.1.6RUN curl -L -o /tmp/redis.tar.gz https://github.com/phpredis/phpredis/archive/3.1.6.tar.gz \ && tar xfz /tmp/redis.tar.gz \ && rm -r /tmp/redis.tar.gz \ && mkdir -p /usr/src/php/ext \ && mv phpredis-3.1.6 /usr/src/php/ext/redis \ && docker-php-ext-install redis \ && rm -rf /usr/src/php# pdo_mysqlRUN cd /usr/local/bin \ && ./docker-php-ext-install pdo_mysql# mongodbRUN curl -L -o /tmp/mongodb.tgz http://pecl.php.net/get/mongodb-1.5.2.tgz \ && tar xfz /tmp/mongodb.tgz \ && mkdir -p /usr/src/php/ext \ && mv mongodb-1.5.2 /usr/src/php/ext/mongodb \ && docker-php-ext-configure mongodb --with-mongodb-ssl \ && docker-php-ext-install mongodb \ && rm -rf /usr/src/php# yafRUN curl -L -o /tmp/yaf-3.0.6.tgz http://pecl.php.net/get/yaf-3.0.6.tgz \ && tar xfz /tmp/yaf-3.0.6.tgz \ && mkdir -p /usr/src/php/ext \ && mv yaf-3.0.6 /usr/src/php/ext/yaf \ && docker-php-ext-install yaf \ && rm -rf /usr/src/phpRUN apt-get -o Acquire::Check-Valid-Until=false update && apt-get install -y libmemcached-dev zlib1g-dev# memcacheRUN curl -L -o /tmp/pecl-memcache-php7.tar.gz https://github.com/websupport-sk/pecl-memcache/archive/php7.tar.gz \ && tar xfz /tmp/pecl-memcache-php7.tar.gz \ && mkdir -p /usr/src/php/ext \ && mv pecl-memcache-php7 /usr/src/php/ext/memcache \ && docker-php-ext-install memcache \ && rm -rf /usr/src/php
# yaf configCOPY docker-php-ext-yaf.ini /usr/local/etc/php/conf.d/docker-php-ext-yaf.ini# supervisorRUN rm -rf /var/lib/apt/lists/* && apt-get -o Acquire::Check-Valid-Until=false update && apt-get install supervisor -yCOPY supervisord.conf /etc/supervisord.conf
# start serviceENTRYPOINT ["/usr/bin/supervisord", "-n", "-c", "/etc/supervisord.conf"]
复制代码


supervisord.conf


; Sample supervisor config file.; ..........[program:php-fpm]command=php-fpmautostart=trueautorestart=truepriority=5stdout_events_enabled=truestderr_events_enabled=true
[program:nginx]command = /usr/local/nginx/sbin/nginx -g 'daemon off;'startsecs=0autostart=trueautorestart=true
[include]files = /etc/supervisor/conf.d/*.conf
复制代码


​ 这里面有一些细节是需要关注的,比如 php-fpm 和 nginx 需要调成前台运行;nginx 和 php-fpm 的参数设置应该参考 Kubernetes POD 申请的 cpu、内存资源进行调整。

1-2 编写 Kubernetes 部署 yaml

​ 业务是无状态工作负载。根据业务需求编写的 yaml 至少包括 deployment 和 service。程序使用到的配置可以本地取(configmap),也可以使用公用的配置中心。需要落地的文件或者日志则使用 pvc 即可(NAS 或者 NFS)。参考 yaml 如下:


---# ----- Deployment --- #apiVersion: apps/v1kind: Deploymentmetadata:  name: fxpdspec:  replicas: 1  selector:    matchLabels:      k8s-app: fxpd  template:    metadata:      labels:        k8s-app: fxpd    spec:      containers:      - name: fxpd-nginx        image: hubstore.com.cn/webrelease/fxpd:latest        ports:        - containerPort: 80        volumeMounts:        - name: fxpd-configfile          mountPath: /opt/config/fxpd      volumes:        - name : fxpd-configfile          configMap:            name: fxpd-configfile---# --- Service --- #kind: ServiceapiVersion: v1metadata:  labels:    k8s-app: fxpd  name: fxpd  namespace: defaultspec:  type: NodePort  ports:    - port: 80      targetPort: 80      nodePort: 30005  selector:    k8s-app: fxpd
复制代码


kubectl create -f xxx.yaml # 默认在default命名空间下
复制代码

二、Python 提供 WEB 服务

​ Python 提供 Web 服务使用的是 Flask、FastAPI 之类的框架,使用 gunicorn 启动。

2-1 基础镜像编译

​ Python 的基础镜像没有 PHP 那么麻烦,基本上基于一个官方的版本即可。基础镜像要保证精简性和较长时间不变动。这里贴出一个 Python 写的服务 Dockerfile 文件。


FROM hubstore.com.cn/base/python:v3
RUN mkdir -p /opt/searchWORKDIR /opt/searchCOPY . /opt/search
RUN yum install mysql-devel -yRUN pip3 install -r requirements.txt -i http://pypi.douban.com/simple --trusted-host pypi.douban.comRUN pip3 install gunicornENV LANG=zh_CN.UTF-8ENV LC_ALL=zh_CN.UTF-8CMD gunicorn -b 0.0.0.0:11000 -w 25 -t 600 startApi:app
复制代码

2-2 编写 Kubernetes 部署 yaml

deployment.yaml


---# ----- Deployment --- #apiVersion: extensions/v1beta1kind: Deploymentmetadata:  name: api  namespace: webapp  labels:    app: api    version: v1spec:  replicas: 2  selector:    matchLabels:      app: api  template:    metadata:      labels:        app: api        version: v1    spec:      imagePullSecrets:      - name: hubstore      containers:      - name: api        image: hubstore.mycloud.com/webapp/api:1.0.190188fl        ports:        - containerPort: 80        resources:            limits:              cpu: '3'              memory: 10000Mi            requests:              cpu: 1500m              memory: 4000Mi        volumeMounts:          - name: api            mountPath: /opt/config/api          - name: cache-volume            mountPath: /dev/shm      volumes:        - name: cache-volume          emptyDir:            medium: Memory            sizeLimit: 2000Mi        - name : apilog          persistentVolumeClaim:            claimName: sfs-api-pvc        - name : api          configMap:            name: api
复制代码


​ 这里面有个特殊的点,是配置了内存 mount 到/dev/shm。这是因为 gunicorn 运行过程中,master 和 worker 保持心跳的目录是/dev/shm。如果不使用内存类型的话,默认是磁盘目录。由于磁盘的效率远低于内存,运行一段时间就会出现 gunicorn 僵住,日志不断报 worker 进程退出。所以想正常在 Kubernetes 中使用 gunicorn,比如做这样的配置。

三、如何编写适合自己业务的 yaml

​ 可以说,一开始使用 Kubernetes 的时候都在编写适合自己的 yaml。目前编写 Kubernetes 相关的 yaml 还没有带提示的编辑器,大部分时候都是自己根据官方的例子和自己积累的经验逐步添加的。


​ 当然除此之外,AWS CDK for Kubernetes 是一个很不错的工具。Python SDK 以编码的形式操作 Kubernetes 资源,然后生成相关的 yaml 文件。虽然目前官方文档对于 Python SDK 这块说明不多,但是翻翻源码是可以找到常用的 k8s 资源的使用方法。我一般是根据这个生成半成品的 yaml 文件,然后再编辑成完整的 yaml 文件。还有,Helm 也是一个常用的工具。不过这块和 CI/CD 关联性比较大,我这里一般第一次项目上线会使用到。


发布于: 刚刚
用户头像

Rayzh

关注

我知道我需要什么 2018.11.13 加入

仅仅是个做运维的...

评论

发布
暂无评论
使用Kubernetes部署应用