距离上次更新正好一个月,因为公司马上要搬家了,最近各种环境的迁移,进公司以后除了负责线上的运维还需要分出精力去搞公司的私有客户,最近终于从私有客户那边抽出来,多写写抓紧入门一下,这篇文章算是应用容器化+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 则是运行这个容器的最后一条命令
实际生产环境会要求镜像包最小化
有一些基础的技巧,可以使最终生成的包大小减少很多。
- dockerfile每条命令相当于在基础镜像上包了一层,所以用连接符减少指令行数
- 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联系方式,欢迎大佬们和我沟通交流,一起学习进步