一.如何部署应用到K8S
当我们需要部署应用时后,考虑是否需要部署到K8S时一般需要考虑上图的几个因素。
1.我们部署应用的架构是怎么样的:比如你要部署redis集群到K8S,就要了解redis集群架构是怎么样的;redis需要怎么样的配置,配置文件怎么加载(环境变量or配置文件),一些云原生的配置文件可以通过加载环境变量,例如rabbitMQ;程序监控端口是什么(redis6379,rabbit5672,15672),启动命令(./redis-server 配置文件 ).
2.镜像谁来做:如果是公司自己的程序,那就自己做。如果是一个中间件,别人开发的,那么镜像在官方都是有的,不需要自己做,官方做的比自己做的好。
3.找合适的部署方式:是否有状态的(倾向无状态应用deployment,中间件很多需要存储挂载PVC),配置分离:一般都是需要把配置文件分离,一些中间件可以通过环境变量加载的,就直接填环境变量,否则配置需要分离出来做成configmap,然后挂载在容器中;
4.然后这个程序如何被使用:什么协议,内部使用还是外部使用,比如redsi使用TCP协议,例如rabbitMQ使用web客户端访问监控端使用http协议,如果是一个TCP协议的内部访问,使用svc名称就可以访问,外部访问的话一般用NODEPORT暴露出去。如果是http协议可以用ingress外部代理出去使用。
二.部署一个单实例到K8S
1、找到官方镜像:https://hub.docker.com/
2、确认需要的配置:环境变量或配置文件
3、选择部署方式:Deployment或其他的
4、配置访问:TCP或HTTP
1.部署rabbitMQ到K8S
首先在官网网站找到rabbitMQ的镜像,搜索选择合适的镜像下载同步到公司的镜像仓库。
确认配置文件:rabbitMQ是可以通过环境变量方式经行配置
然后确认部署方式:由于rabbitMQ是单实例,所以可以用deployment部署,消息队列一般要保存数据做持久化,所以也要挂载PVC(挂载目录/var/lib/rabbitmq)。
写deployment,pvc部署文件,可以官网找模板自己改:
[root@k8s-master01 ~]# vim rabbitMQ-deployment.yaml apiVersion: v1 kind: Service metadata: name: rabbitmq namespace: public-service spec: ports: - name: web port: 5672 protocol: TCP targetPort: 5672 - name: http port: 15672 protocol: TCP targetPort: 15672 selector: app: rabbitmq sessionAffinity: None type: NodePort --- apiVersion: apps/v1 kind: Deployment metadata: annotations: {} labels: app: rabbitmq name: rabbitmq namespace: public-service spec: replicas: 1 selector: matchLabels: app: rabbitmq strategy: rollingUpdate: maxSurge: 1 maxUnavailable: 0 type: RollingUpdate template: metadata: creationTimestamp: null labels: app: rabbitmq spec: affinity: {} containers: - env: - name: TZ value: Asia/Shanghai - name: LANG value: C.UTF-8 - name: RABBITMQ_DEFAULT_USER #通过环境变量配置默认管理员用户密码 value: user - name: RABBITMQ_DEFAULT_PASS value: password image: rabbitmq:3.8.17-management imagePullPolicy: IfNotPresent lifecycle: {} livenessProbe: failureThreshold: 2 initialDelaySeconds: 30 periodSeconds: 10 successThreshold: 1 tcpSocket: port: 5672 timeoutSeconds: 2 name: rabbitmq ports: - containerPort: 5672 name: web protocol: TCP readinessProbe: failureThreshold: 2 initialDelaySeconds: 30 periodSeconds: 10 successThreshold: 1 tcpSocket: port: 5672 timeoutSeconds: 2 resources: limits: cpu: 1000m memory: 1024Mi requests: cpu: 250m memory: 500Mi restartPolicy: Always [root@k8s-master01 ~]# kubectl create ns public-service #单独创建一个命名空间 [root@k8s-master01 ~]# kubectl create -f rabbitMQ-deployment.yaml [root@k8s-master01 ~]# kubectl get pod -n public-service NAME READY STATUS RESTARTS AGE rabbitmq-77b5d5b747-6nl55 1/1 Running 3 2d [root@k8s-master01 ~]# kubectl get svc -n public-service NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE rabbitmq NodePort 10.108.113.166 5672:31142/TCP,15672:31317/TCP 2d1h
然后通过NodePort暴露一个端口访问,通过暴露的端口访问(用http)
http://192.168.0.236:32424/#/
三.传统架构和K8S管理中间件的区别
1.区别
传统架构:
如下图,比较复杂
k8s架构:
一句话总结功能就是可以很方便管理一些比较复杂的应用,比如MySQL集群、Redis集群等,可以一键式创建集群、扩容、备份等。常用的两种包管理工具是Operator和Helm。
helm:倾向于无状态应用的部署,比如公司的服务、某些不需要持久化数据的中间件、不需要实现额外功能的服务,比如备份、回滚等(比较容易)。
Operator:管理更为复杂的有状态服务,比如MySQL集群、Redis集群、Rook等。并且可以利用Operator实现扩容、备份、回滚等功能.(功能需要写代码实现,比较复杂)
2.中间件到底要不要部署在K8s
非生产环境:使用K8s管理比较推荐
非生产环境的中间件推荐所有都装在K8S中,一般测试环境不用考虑性能,稳定性,数据不需要持久化(mysql除外),也可以用动态存储rook。
生产环境:需要考虑性能、持久化、稳定性等问题。
mysql对磁盘IO要求比较高,一般可以考虑用云厂商的数据库。
生产环境需要考虑的比较多,一般结合项目需求,
四.Operator的使用
1.Operator部署redis集群
Operator常用的模板:https://github.com/operator-framework/awesome-operators
Redis Cluster Operator: https://github.com/ucloud/redis-cluster-operator
首先要先创建一些自定义的资源,K8S有很多kind,Operator可以管理这些创建的自定义kind
1、创建Operator-redis
git clone https://github.com/ucloud/redis-cluster-operator.git cd redis-cluster-operator/ kubectl create -f deploy/crds/redis.kun_distributedredisclusters_crd.yaml kubectl create -f deploy/crds/redis.kun_redisclusterbackups_crd.yaml kubectl create ns redis-cluster #通过集群的方式创建,如果需要创建另一个集群,再创建一个redis-cluster2,同样执行下面4条命令即可 kubectl create -f deploy/service_account.yaml -n redis-cluster kubectl create -f deploy/namespace/role.yaml -n redis-cluster kubectl create -f deploy/namespace/role_binding.yaml -n redis-cluster kubectl create -f deploy/namespace/operator.yaml -n redis-cluster
查看operator-redis:
[root@k8s-master01 redis-cluster-operator]# kubectl get pod -n redis-cluster NAME READY STATUS RESTARTS AGE redis-cluster-operator-675ccbc697-gz6fw 1/1 Running 0 23s
2、创建redis集群
此文件可以定义集群的规模
[root@k8s-master01 redis-cluster-operator]# vim deploy/example/redis.kun_v1alpha1_distributedrediscluster_cr.yaml apiVersion: redis.kun/v1alpha1 kind: DistributedRedisCluster metadata: annotations: # if your operator run as cluster-scoped, add this annotations redis.kun/scope: cluster-scoped name: example-distributedrediscluster spec: # Add fields here masterSize: 3 #master节点数 clusterReplicas: 1 #每个主节点有几个从节点 image: redis:5.0.4-alpine #使用的镜像版本
创建:
[root@k8s-master01 redis-cluster-operator]# kubectl create -f deploy/example/redis.kun_v1alpha1_distributedrediscluster_cr.yaml -n redis-cluster 【可选】提示:如果集群规模不大,资源少,可以自定义资源,把请求的资源降低 kubectl create -f deploy/example/custom-resources.yaml -n redis-cluster
3、扩容Redis集群
扩容Redis集群
grep "master" deploy/example/redis.kun_v1alpha1_distributedrediscluster_cr.yaml masterSize: 4 kubectl replace -f deploy/example/redis.kun_v1alpha1_distributedrediscluster_cr.yaml -n redis-cluster
4、卸载集群
kubectl delete -f deploy/example/redis.kun_v1alpha1_distributedrediscluster_cr.yaml -n redis-cluster kubectl delete -f deploy/cluster/operator.yaml -n redis-cluster kubectl delete -f deploy/cluster/cluster_role_binding.yaml -n redis-cluster kubectl delete -f deploy/cluster/cluster_role.yaml -n redis-cluster kubectl delete -f deploy/service_account.yaml -n redis-cluster kubectl delete -f deploy/crds/redis.kun_redisclusterbackups_crd.yaml -n redis-cluster kubectl delete -f deploy/crds/redis.kun_distributedredisclusters_crd.yaml -n redis-cluster
五.Helm的使用
1.使用Helm创建Kafka、Zookeeper集群
首先安装heml,并添加仓库
a.下载安装包:https://github.com/helm/helm/releases
b.解压:tar -zxvf helm-v3.0.0-linux-amd64.tar.gz
c.复制到二进制目录:mv linux-amd64/helm /usr/local/bin/helm
[root@k8s-master01 bin]# which helm #查看 /usr/local/bin/helm
d.添加bitnami和官方helm仓库:
[root@k8s-master01 ~]# helm repo add bitnami https://charts.bitnami.com/bitnami [root@k8s-master01 ~]# helm repo add stable https://charts.helm.sh/stable
e.基础命令:
下载一个包:helm pull 创建一个包:helm create 安装一个包:helm install 查看:helm list 查看安装参数:helm get values 更新:helm upgrade 删除:helm delete
f.安装方式一:先下载后安装
[root@k8s-master01 ~]# helm pull bitnami/zookeeper
[root@k8s-master01 ~]# tar xf zookeeper-7.5.1.tgz #解压
[root@k8s-master01 ~]# cd zookeeper && vim values.yaml #修改values.yaml相应配置:副本数、auth、持久化
image:镜像地址 replicaCount: 3 #副本数 persistence: 设置持久化,storageClass: sc-pvc名称
helm install -n public-service zookeeper . #安装
g.安装方式二:直接安装kafka
通过命名方式直接设置环境变量参数
[root@k8s-master01 zookeeper]# helm install kafka bitnami/kafka --set zookeeper.enabled=false --set replicaCount=3 --set externalZookeeper.servers=zookeeper --set persistence.enabled=false -n public-service [root@k8s-master01 zookeeper]# kubectl get pod -n public-service #2个集群都启动完成 NAME READY STATUS RESTARTS AGE kafka-0 1/1 Running 0 4m11s kafka-1 1/1 Running 0 4m11s kafka-2 1/1 Running 0 4m11s zookeeper-0 1/1 Running 0 23m zookeeper-1 1/1 Running 0 23m zookeeper-2 1/1 Running 0 23m [root@k8s-master01 ~]# kubectl get svc -n public-service #查看SVC NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kafka ClusterIP 10.104.163.229092/TCP 17m kafka-headless ClusterIP None 9092/TCP,9093/TCP 17m zookeeper ClusterIP 10.105.133.146 2181/TCP,2888/TCP,3888/TCP 37m zookeeper-headless ClusterIP None 2181/TCP,2888/TCP,3888/TCP 37m
2.Kafka验证
先起一个kafka客户端验证
kafka客户端:kubectl run kafka-client –restart=’Never’ –image docker.io/bitnami/kafka:2.8.0-debian-10-r30 –namespace public-service –command — sleep infinity
[root@k8s-master01 zookeeper]# kubectl get pod -n public-service | grep client
kafka-client 1/1 Running 0 39s
模拟生产者
[root@k8s-master01 zookeeper]# kubectl exec --tty -i kafka-client --namespace public-service -- bash #进入kafka I have no name!@kafka-client:/$ kafka-console-producer.sh \ > --broker-list kafka-0.kafka-headless.public-service.svc.cluster.local:9092,kafka-1.kafka-headless.public-service.svc.cluster.local:9092,kafka-2.kafka-headless.public-service.svc.cluster.local:9092 \ > --topic test >1 >test 2 >xiaofei 1 >xiaofei2^H >wo123
模拟消费者 [root@k8s-master01 ~]# kubectl exec --tty -i kafka-client --namespace public-service -- bash I have no name!@kafka-client:/$ kafka-console-consumer.sh \ > --bootstrap-server kafka.public-service.svc.cluster.local:9092 \ > --topic test \ > --from-beginning 1 test 2 xiaofei 1 xiaofei wo123
集群能正常消费,无异常
3.Kafka更新删除
更新和安装差不多,用heml upgrade更新
1.Kafka更新:
命令方式:
[root@k8s-master01 ~]# helm upgrade kafka bitnami/kafka --set zookeeper.enabled=false --set replicaCount=5 --set externalZookeeper.servers=zookeeper --set persistence.enabled=false -n public-service #副本数改成5
yaml文件方式:
[root@k8s-master01 ~]# [root@k8s-master01 ~]# vim zookeeper/values.yaml [root@k8s-master01 ~]# helm upgrade -n public-service zookeeper .
2.Kafka删除:
[root@k8s-master01 ~]# helm list -A #查看helm数 NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION kafka public-service 1 2021-12-16 18:21:58.629211542 +0800 CST deployed kafka-14.7.1 2.8.1 zookeeper public-service 1 2021-12-16 18:02:36.300204363 +0800 CST deployed zookeeper-7.5.1 3.7.0 [root@k8s-master01 ~]# helm delete -n publice-service fafka zookeeper #删除即可
六.Helm的目录层级
创建一个Chart:helm create helm-test ├── charts # 依赖文件 ├── Chart.yaml # 当前chart的基本信息 apiVersion:Chart的apiVersion,目前默认都是v2 name:Chart的名称 type:图表的类型[可选] version:Chart自己的版本号 appVersion:Chart内应用的版本号[可选] description:Chart描述信息[可选] ├── templates # 模板位置 │ ├── deployment.yaml │ ├── _helpers.tpl # 自定义的模板或者函数 │ ├── ingress.yaml │ ├── NOTES.txt #Chart安装完毕后的提醒信息 │ ├── serviceaccount.yaml │ ├── service.yaml │ └── tests # 测试文件 │ └── test-connection.yaml └── values.yaml #配置全局变量或者一些参数
主要是values.yaml,定义全局变量,可以自定义参数,然后templates模板文件可以引用上面的变量,需要自己定义。
渲染配置文件,并不生成方式:会生成内置模板的yaml,包含sa,svc,deployment等自定义yaml。
[root@k8s-master01 helm-test]# helm install helm-test . --dry-run NAME: helm-test LAST DEPLOYED: Fri Dec 17 11:47:39 2021 NAMESPACE: default STATUS: pending-install REVISION: 1 HOOKS: --- # Source: helm-test/templates/tests/test-connection.yaml apiVersion: v1 kind: Pod metadata: name: "helm-test-test-connection" labels: helm.sh/chart: helm-test-0.1.0 app.kubernetes.io/name: helm-test app.kubernetes.io/instance: helm-test app.kubernetes.io/version: "1.16.0" app.kubernetes.io/managed-by: Helm annotations: "helm.sh/hook": test spec: containers: - name: wget image: busybox command: ['wget'] args: ['helm-test:80'] restartPolicy: Never MANIFEST: --- # Source: helm-test/templates/serviceaccount.yaml apiVersion: v1 kind: ServiceAccount metadata: name: helm-test labels: helm.sh/chart: helm-test-0.1.0 app.kubernetes.io/name: helm-test app.kubernetes.io/instance: helm-test app.kubernetes.io/version: "1.16.0" app.kubernetes.io/managed-by: Helm --- # Source: helm-test/templates/service.yaml apiVersion: v1 kind: Service metadata: name: helm-test labels: helm.sh/chart: helm-test-0.1.0 app.kubernetes.io/name: helm-test app.kubernetes.io/instance: helm-test app.kubernetes.io/version: "1.16.0" app.kubernetes.io/managed-by: Helm spec: type: ClusterIP ports: - port: 80 targetPort: http protocol: TCP name: http selector: app.kubernetes.io/name: helm-test app.kubernetes.io/instance: helm-test --- # Source: helm-test/templates/deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: helm-test labels: helm.sh/chart: helm-test-0.1.0 app.kubernetes.io/name: helm-test app.kubernetes.io/instance: helm-test app.kubernetes.io/version: "1.16.0" app.kubernetes.io/managed-by: Helm spec: replicas: 1 selector: matchLabels: app.kubernetes.io/name: helm-test app.kubernetes.io/instance: helm-test template: metadata: labels: app.kubernetes.io/name: helm-test app.kubernetes.io/instance: helm-test spec: serviceAccountName: helm-test securityContext: {} containers: - name: helm-test securityContext: {} image: "nginx:1.16.0" imagePullPolicy: IfNotPresent ports: - name: http containerPort: 80 protocol: TCP livenessProbe: httpGet: path: / port: http readinessProbe: httpGet: path: / port: http resources: {} NOTES: 1. Get the application URL by running these commands: export POD_NAME=$(kubectl get pods --namespace default -l "app.kubernetes.io/name=helm-test,app.kubernetes.io/instance=helm-test" -o jsonpath="{.items[0].metadata.name}") export CONTAINER_PORT=$(kubectl get pod --namespace default $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") echo "Visit http://127.0.0.1:8080 to use your application" kubectl --namespace default port-forward $POD_NAME 8080:$CONTAINER_PORT
七.Helm的内置变量
heml有些变量是没有在values中设置的,叫内置变量,如下常见内置变量:
Release.Name: 实例的名称,helm install指定的名字
Release.Namespace: 应用实例的命名空间
Release.IsUpgrade: 如果当前对实例的操作是更新或者回滚,这个变量的值就会被置为true
Release.IsInstall: 如果当前对实例的操作是安装,则这边变量被置为true
Release.Revision: 此次修订的版本号,从1开始,每次升级回滚都会增加1
Chart: Chart.yaml文件中的内容,可以使用Chart.Version表示应用版本,Chart.Name表示Chart的名称