云原生时代,拥抱微服务(二)—— 容器化应用

前文我们已经搭建好k8s集群,接下来就可以对部分项目进行容器化改造了。

“万丈高楼平地起,敲好代码是关键。” —— 皮皮叨叨

创建镜像文件Dockerfile

以Node.js应用为例:

FROM node:12-alpine

# install tzdata so that we can set timezone which default is UTC
RUN apk add tzdata
ENV TZ Asia/Shanghai

# set our node environment, either development or production
# defaults to production, can override this to development on build and run
ARG NODE_ENV=production
ENV NODE_ENV $NODE_ENV

# default to port 3000 for node, and 9229 and 9230 (tests) for debug
ARG PORT=3000
ENV PORT $PORT
EXPOSE $PORT 9229 9230

# install dependencies first, in a different location for easier app bind mounting for local development
# due to default /opt permissions we have to create the dir with root and change perms
RUN mkdir /your-app && chown node:node /your-app
RUN mkdir /var/log/your-app && chown node:node /var/log/your-app
WORKDIR /your-app
# the official node image provides an unprivileged user as a security best practice
# but we have to manually enable it. We put it here so yarn installs dependencies as the same
# user who runs the app.
# https://github.com/nodejs/docker-node/blob/master/docs/BestPractices.md#non-root-user
USER node
COPY --chown=node:node . .
RUN yarn install --production=true
ENV PATH /your-app/node_modules/.bin:$PATH

CMD [ "yarn", "start" ]

PS: .dockerignore文件可通过gitignore.io生成。

应用配置信息及密钥管理

普通配置信息

ConfigMaps是一种Kubernetes资源,允许你为容器保存配置信息,这些配置后续可以通过挂载为容器的环境变量或者文件进行访问。

# your-config.yaml
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: your-api
data:
  mongodb_host: your.mongodb.host
  mongodb_database: your-database-name

通过在k8s集群中使用kubectl apply命令创建上述命名为your-apiConfigMap资源(如果该资源已经存在,则进行更新动作)。

kubectl apply -f path-to/your-config

密钥等敏感信息

不像ConfigMapsSecrets是一种用于存放敏感信息的Kubernetes资源,一般可用于存放各类凭证、ssh密钥,TLS密钥及证书,或者其他在应用中需要使用的敏感数据。Secrets同样可以挂载为容器的环境变量或者文件。

Secrets被保存为base64编码的字符串,我们需要在Secrets声明文件中将对应敏感信息(如数据库用户名与密码)转换为base64格式。可使用如下命令:

echo -n "db-user-name" | base64
# output: ZGItdXNlci1uYW1l

echo -n "db-pwd" | base64
# output: ZGItcHdk

注意,上述命令输出后的base64编码字符串就是我们需要保持到Kubernetes中的Secrets信息。

# your-secrets.yaml
---
apiVersion: v1
kind: Secret
metadata:
  name: your-api
data:
  mongodb_username: ZGItdXNlci1uYW1l
  mongodb_password: ZGItcHdk

使用kubectl apply命令创建对应Secrets资源:

kubectl apply -f path-to/your-secrets.yaml

【温馨提示】base64编码的字符串并不是被加密的,需要将上述Secrets声明文件保存到足够安全的地方,并且防止泄露!!!建议在Kubernetes集群中统一进行管理。

为应用程序创建Deployment工作负载

工作负载(Workloads)资源可以理解为在Kubernetes中的应用程序,主要包括:DeploymentStatefulSetDaemonSetJobCronJob等类型。

Deployment主要用于扩展与更新无状态容器Pod,适用于我们无状态的应用程序。Deployment会自动创建副本集(ReplicaSet)资源,以用于替换失败的Pods,弹性扩展或减少Pods

# your-deployment.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: your-api
  labels:
    app: your-api-label
spec:
  replicas: 3
  selector:
    matchLabels:
      app: your-api-label
  template:
    metadata:
      labels:
        app: your-api-label
    spec:
      containers:
        - name: your-api
          image: your-api-image:1.0.0
          env:
            - name: MONGODB_HOST
              valueFrom:
                configMapKeyRef:
                  name: your-api
                  key: mongodb_host
            - name: MONGODB_DATABASE
              valueFrom:
                configMapKeyRef:
                  name: your-api
                  key: mongodb_database
            - name: MONGODB_USER
              valueFrom:
                secretKeyRef:
                  name: your-api
                  key: mongodb_username
            - name: MONGODB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: your-api
                  key: mongodb_password

使用kubectl apply命令创建对应Deployment资源:

kubectl apply -f path-to/your-depoyment.yaml

使用Service公开Deployment工作负载

我们还需要通过创建Service资源以更好地访问不同Pod中的应用程序,并且能做到负载均衡。这主要是由于Pod是短暂的,一旦由于某种原因被销毁,其对应的IP地址也会被吊销,然后新生的Pod将获得一个不同的IP地址。

# your-service.yaml
---
apiVersion: v1
kind: Service
metadata:
  name: your-api
spec:
  type: ClusterIP
  selector:
    app: your-api-label
  ports:
    - protocol: TCP
      port: 80
      targetPort: http

使用kubectl apply命令创建对应Service资源:

kubectl apply -f path-to/your-service.yaml

总结

我们首先通过创建Dockerfile以用于生成应用程序的容器镜像,然后通过使用ConfigMapsSecrets资源管理应用程序的配置及敏感信息,最后再运用DeploymentService资源部署及公开应用程序。

微服务高楼的基石貌似已经搭好了,胜利的曙光就在眼前。但是机智且追求效率的你一定发现了:一个应用程序这样做还好,可如果有多个应用程序也需要容器化,都分别去声明各种Kubernetes资源岂不是很繁琐?你这个ClusterIP类型的Service似乎还无法从外网访问?