业务系统与中间件k8s容器化部署实践——redis+nodejs/springboot单体应用

1.redis k8s部署

1.1创建创建一个namespace,缺省为default,创建套路kubectl apply -f XX.yaml

apiVersion: v1
kind: Namespace
metadata:
  name: redis-namespace

1.2创建一个configmap,建议去掉redis.conf原配置文件里的注释,减少etcd存储消耗

kubectl create configmap redis-configmap --from-file=/etc/redis.conf -n redis-namespace

1.3宿主机/etc/redis.conf配置文件

​
dir /data    
requirepass 12345    

pidfile /data/redis.pid
port 6379
tcp-backlog 30000
timeout 0
tcp-keepalive 10
loglevel notice
logfile /data/redis.log
databases 16
#save 900 1
#save 300 10
#save 60 10000
stop-writes-on-bgsave-error no
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
slave-serve-stale-data yes
slave-read-only yes
repl-diskless-sync no
repl-diskless-sync-delay 5
repl-disable-tcp-nodelay no
slave-priority 100
maxclients 30000
appendonly no
appendfilename "appendonly.aof"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
lua-time-limit 5000
slowlog-log-slower-than 10000
slowlog-max-len 128
latency-monitor-threshold 0
notify-keyspace-events KEA
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
list-max-ziplist-entries 512
list-max-ziplist-value 64
set-max-intset-entries 1000
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
hll-sparse-max-bytes 3000
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit slave 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10

​

1.4创建一个deployment ,创建套路kubectl apply -f XXX.yaml ,这里数据卷一个挂载上面定义的configmap,一个宿主机hostPath

apiVersion: extensions/v1beta1  #注意v1版本不支持Deployment
kind: Deployment
metadata:
  name: redis-deployment
  namespace: redis-namespace    #使用自定义namespace
spec:
  replicas: 1   
  template:
    metadata:
     labels:
       name: redis-label
    spec:
     containers:
     - name: redis-container
       image: redis
       volumeMounts:
       - name: myconfigmap     #与volumes的name对应
         mountPath: "/usr/local/etc"   #与vomums的key为redis.conf的path拼接得到容器内redis配置文件绝对路径
       - name: redis-data             #容器内挂载点名称
         mountPath: /data    #容器内data保持路径,该路径在redis.conf配置了
       command:
         - "redis-server"   #启动命令
       args:
         - "/usr/local/etc/redis/redis.conf"  #带配置文件启动
     volumes:
     - name: myconfigmap
       configMap:
         name: redis-configmap  #指定使用的configmap
         items:
           - key: redis.conf  #该值为configmap创建--from-file的文件名
             path: redis/redis.conf
     - name: redis-data          #数据卷名称,需要与容器内挂载点名称一致
       hostPath:
          path: /var/lib/redis   #将容器挂载点名称相同的path挂载到宿主机path(但这种方式有局限性,pod分配到其它node数据就丢失了,需要挂载到NFS文件系统?)

1.5测试

#查看
kubectl get pods -n redis-namespace -o wide

#进入容器访问
kubectl exec -it redis-deployment-556c5d85bb-vxv6b   /bin/bash   -n redis-namespace

#redis操作测试
连接redis-cli  认证auth 12345  查看数据目录:/var/lib/redis 

#暴露redis-deployment这个服务,方便后面被其它k8s容器,并暴露一个外网端口(正式环境一般中间件不暴露外网端口)
kubectl expose deployment redis-deployment -n redis-namespace --port=6379  --type=LoadBalancer

#检查该服务
kubectl get service -n redis-namespace 
内容为redis-deployment   LoadBalancer   10.1.59.127   <pending>     6379:30753/TCP
测试连接:telnet 127.0.0.1 30753   telnet 10.1.59.127 6379

2.业务应用 k8s部署

为方便这里以nodejs为例,Java应用类似.
2.1.需要node环境,node -v ,没有就安装一下yum install node -y
2.2 nodejs业务程序,文件内容如下

var http=require('http');
  var handleRequest = function(request, response) {
      console.log('Received request for URL: ' + request.url);
      response.writeHead(200);
      response.end('Hello World!');

   };
   var www = http.createServer(handleRequest);
   www.listen(8080);

2.3 直接启动一下:node server.js,测试:curl  127.0.0.1:8080 

2.4 在service.js同级目录,创建Dockerfile,如果使用java可使用基础镜像FROM java:8,文件内容如下


   FROM node:6.9.2
   EXPOSE 8080
   COPY server.js .
   CMD node server.js

  2.5 镜像构建并推送到docker registry私库

1.安装registry仓库
docker run -d -v /opt/registry:/var/lib/registry -p 5000:5000 --name myregistry registry:2

2.构建nodejs应用镜像192.168.203.134:5000/hello-world:v1
docker build -t 192.168.203.134:5000/hello-world:v1 .
docker push 192.168.203.134:5000/hello-world:v1 .

3.docker push默认走https协议,如果要http协议push,需要配置/etc/docker/daemon.json,内容为:{
  "registry-mirrors": ["https://5c3uuctj.mirror.aliyuncs.com","https://hub- mirror.c.163.com", "https://reg-mirror.qiniu.com"],
  "insecure-registries":["192.168.203.134:5000"]
}
4.重启:systemctl restart docker && docker restart myregistry ,再推送
 docker push 192.168.203.134:5000/hello-world:v1 .
5.检查一下
curl http://192.168.203.134:5000/v2/_catalog

2.6  k8s 部署hello-world

1.启动容器
kubectl run hello-world --image=192.168.203.134:5000/hello-world:v2 --port=8080
2.暴露该服务一个外网可访问的随机IP
kubectl expose deployment hello-world --type=LoadBalancer
3.查看与测试
kubectl get services 
curl 192.168.203.134:随机IP 或 ClusterIp:8080

3.k8s业务容器访问k8s redis容器

3.1代码修改,引入redis模块,service.js目录npm install redis安装redis依赖,使用nodejs读写redis,连接参数REDIS_PORT,REDIS_HOST从环境变量读取:process.env.REDIS_PORT,process.env.REDIS_HOST

var http=require('http');
var redis=require('redis');
var handleRequest = function(request, response) {
      console.log('Received request for URL: ' + request.url);
      RDS_PORT = process.env.REDIS_PORT,
      RDS_HOST = process.env.REDIS_HOST,
      RDS_OPTS = {auth_pass:12345} ,
      client = redis.createClient(RDS_PORT, RDS_HOST, RDS_OPTS);

client.on('ready', function(res){
        console.log('redis连接事件')
         })

client.set("now",new Date(),redis.print);
client.get("now", function(err, reply){
        console.log(reply);
        response.writeHead(200);
        response.end('当前时间:'+reply);
         })

  };
var www = http.createServer(handleRequest);
www.listen(8080);

3.2 修改Dockerfile,CMD命令增加npm intall redis,否则后面启动k8s应用容器报错缺少redis模块(kubectl logs POD名称)


FROM node:6.9.2
EXPOSE 8080
COPY server.js .
CMD npm install redis && node server.js

3.3重新构建推送私库并k8s部署

1.重新构建并推送
docker build -t 192.168.203.134:5000/hello-world:v2 .
docker push 192.168.203.134:5000/hello-world:v2
2.更新k8s hello-world服务的镜像,重新kubectl apply -f XXX.yaml,
或kubectl set image deployment/hello-world hello-world=192.168.203.134:5000/hello-world:v2
3.查看日志
kubectl get service,pod 获取pod名称
kubectl  logs --tail 222 -f  pod/hello-world-699d4b48cb-r4tpb 进行动态查看日志

日志内容是这样的,因为service.js的redis连接参数需要读取环境变量process.env.REDIS_PORT,process.env.REDIS_HOST,而

通过kubectl run xx kubectl expose xx这样直接部署一个deployment不便指定环境变量及其它,需要使用yaml配置文件方式启动

3.4 通过yaml配置文件启动redis-deployment, kubectl apply -f xxxx.yaml

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: hello-world
  namespace: default #不一定要与其它服务如redis-deployment在同一命名空间
spec:
  replicas: 1
  selector:
    matchLabels:
      app: myweb
  strategy:
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: myweb
    spec:
      containers:
      - name: hello-world
        image: 192.168.203.134:5000/hello-world:v2
        volumeMounts:
        - name: time-zone
          mountPath: /etc/localtime
        ports:
        - containerPort: 8080
        env:
        - name: REDIS_HOST
          value: 192.168.203.134  #10.1.59.127   #redis-deployment这个service暴露外网nodePort,可以通过外网IP:NodePort或CLUSTER_IP:8080访问
        - name: REDIS_PORT
          value: "30753"          #"6379"
      volumes:
      - name: time-zone
        hostPath:
          path: /etc/localtime

3.5 测试

1.删除原deployment,service可以不删
kubectl delete  deployment hello-world
2.启动k8s容器服务
kubectl apply -f XXX.yaml
3.查看日志
kubectl get pods
kubectl  logs --tail 222 -f  pod/hello-world-68995967dd-hq9c6

请求测试与hello-world的pod日志输出

3.6 REDIS_PORT,REDIS_HOST改为configmap读取,重新kubectl apply .

1.创建configmap
kubectl create configmap redis-config --from-literal=redis.port=6379 --from-literal=redis.host=10.1.59.127

2.hello-world的deployment yaml资源描述env部分修改如下:

        env:
        - name: REDIS_HOST
          valueFrom:                 
            configMapKeyRef:
              name: redis-config
              key: redis.host
        - name: REDIS_PORT
          valueFrom:                  
            configMapKeyRef:
              name: redis-config
              key: redis.port

3.7 springboot单体应用部署

1.修改Dockerfile的基础镜像,CMD启动命令的区别等

2.查看application-dev.yml REDIS主要连接参数如下:
spring:
  redis:
    host: XXXX
    port: 6379
key为spring.redis.host spring.redis.port 

3.创建configmap:kubectl create configmap redis-config --from-literal=redis.port=6379 --
from-literal=redis.host=10.1.59.127

4.deployment资源描述文件env部分指定spring.redis.host spring.redis.port这两个变量的值
         env:
        - name: spring.redis.host
          valueFrom:                 
            configMapKeyRef:
              name: redis-config
              key: redis.host
        - name: spring.redis.port
          valueFrom:                  
            configMapKeyRef:
              name: redis-config
              key: redis.port

3.8 关于数据持久化 

k8s pod分配是动态的,redis数据目录挂载到宿主机很可能造成数据丢失,需要向configmap一样的NFS进行集中存储(参考https://www.cnblogs.com/DaweiJ/articles/9131762.html),或REDIS等系统不进行k8s容器化部署

 

 


版权声明:本文为qq_39506978原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。