如何将服务运行在k8s中

距离上次更新正好一个月,因为公司马上要搬家了,最近各种环境的迁移,进公司以后除了负责线上的运维还需要分出精力去搞公司的私有客户,最近终于从私有客户那边抽出来,全心投入到公有云的线上运维来了!开始找俊奇大佬要一些简单的需求,写一写接口,多写写抓紧入门一下,这篇文章算是应用容器化+k8s上线的入门教程了

如何将服务运行在k8s中

环境准备

这篇文章建立在,已经准备好了如下的环境的基础上,如果没有可以找找教程,自行测试k8s太重的话可以弄轻量的k3s都可以

  • python3,docker
  • k8s,私有仓库

开发过程

因为刚写python,所以这里以python的代码为例,其他语言的均类似
下面是简单的Hello world进程,程序默认的监听端口是8080
(当然在我们生产上会有很多复杂的场景,这里只介绍基本情况,就是服务只监听一个端口的情形)

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello world!"

if __name__ == "__main__":
    app.run()

容器化

接下来就是怎么将各种语言写的代码容器化的操作了
以python为例,dockerfile很简单

FROM python:3.6.4
RUN mkdir /code \
    &&apt-get update \
    &&apt-get -y install freetds-dev \
    &&apt-get -y install unixodbc-dev
COPY . /code 
COPY requirements.txt /code
RUN pip install -r /code/requirements.txt -i https://pypi.douban.com/simple
WORKDIR /code
CMD ["python3","/code/xx.py","8060"]

FROM一个基础环境,如果你是node开发from一个node的镜像作为基础环境
RUN 是构建镜像过程中执行指令,这里是运行安装一些基础依赖,这个根据应用来
基础依赖安装完成后,将代码,以及python依赖的库安装一下
CMD 则是运行这个容器的最后一条命令

实际生产环境会要求镜像包最小化
有一些基础的技巧,可以使最终生成的包大小减少很多。

  1. dockerfile每条命令相当于在基础镜像上包了一层,所以用连接符减少指令行数
  2. multistage builds 这个很好用

下面以实际生产中multistage为例:

  FROM xxx/node:6.11.2 AS builder
  WORKDIR /app
  COPY package.json ./package.json
  COPY yarn.lock ./
  RUN yarn install  && yarn cache clean
  FROM node:6.11.2
  WORKDIR /xxx
  COPY --from=builder /xxx/node_modules /xxx/node_modules
  COPY . .
  EXPOSE 5000
  CMD npm start

生产中尽量把构建过程拆分开,最终镜像只需要从过程镜像获取构建好的依赖

私有仓库

这里不过多介绍,镜像推送私有仓库很简单

docker build -t xxx:v0.0.1 .  
docker push xxxx:v0.0.1  

kubernetes创建应用

下面我先附上deploy文件,再介绍下里面的内容

apiVersion: v1
kind: Service
metadata:
  name: xxx(应用名)
  namespace: release(namespace名)
  labels:
    app: xxx(应用名)
    service: xxx(应用名)
spec:
  ports:
  - port: 8060
    name: http
  selector:
    app: xxx(应用名)
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: xxx(应用名)
  namespace: release(namespace名)
  labels:
    app: xxx(应用名)
    version: v1
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: xxx(应用名)
        version: v1
    spec:
      containers:
      - name: xxx(应用名)
        image: xxx:v0.0.1(这里是我们刚推送到私有仓库的地址)
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8060

这里我创建了两个资源,kind分别是service和deployment
service用于将port映射出去
deployment描述pod信息
因为我这里服务只需要内部调用,所以这里没有将端口暴露出去
实际生产环境中,除了需要暴露端口,类似证书,配置文件均可以通过configmap的形式挂载到pod中去

apiVersion: v1
kind: Service
metadata:
  name: appnamexx
  namespace: namespacexx
  labels:
    app: appnamexx
spec:
  selector:
    app: appnamexx
  type: NodePort
  ports:
  - name: appnamexx
    port: portxx
    nodePort: nodeportxx
    protocol: TCP
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name:  appnamexx
  namespace: namespacexx
spec:
  minReadySeconds: 5
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
  replicas: replicas
  template:
    metadata:
      labels:
        app:  appnamexx
    spec:
      securityContext:
        runAsUser: someuserxx
        fsGroup: somegroupxx
      containers:
      - name: appnamexx
        image: imageaddrxx
        resources:
          limits:
            cpu: 100m
            memory: 1000Mi
          requests:
            cpu: 100m
            memory: 500Mi
        livenessProbe:
          httpGet:
            path: /checkalive
            port: portxx
            scheme: HTTP
          initialDelaySeconds: 60
          timeoutSeconds: 5
        readinessProbe:
          httpGet:
            path: /probe
            port: portxx
            scheme: HTTP
          initialDelaySeconds: 3
          timeoutSeconds: 5
        ports:
        - containerPort: portxx
          name: http
          protocol: TCP
        env:
          - name: SOME_ENVXX
            value: xxx
        volumeMounts:
          - name: configvolumexx
            mountPath: configpathxx
      volumes:
      - name: configvolumexx
        configMap:
          name: app's config

可以看到生产环境多了很多配置,除了nodeport将应用的端口映射出去
还增加了类似pod内存,cpu资源分配的限制
配置文件的挂载,注意volumes和volumeMounts对应的name要一致,并且这个名字和k8s的configmap的资源名都保持一致才能将congfigmap挂载到对应的pod中去

上线&调试

上线就是apply对应的资源,最终调试可以参考上一篇讲nginx时讲到的本地调试方式进行本地调试,本地开发环境并不需要打包到镜像并发送到k8s的pod才能调试。只需在nginxcallback到本地的端口即可

欢迎大佬交流探讨

页面中有邮箱和github联系方式,欢迎大佬们和我沟通交流,一起学习进步

打赏一个呗

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦