如果想要在K8S环境上部署某软件的话,那么首先先要了解的是该软件在Bare Metal裸金属环境下的手动安装方式、如何配置,启动等等;然后再考虑如何将软件Docker化,怎么编写Dockerfile,Docker环境下如何配置、启动等。最后根据之前Docker的方式选用K8S的YAML资源来创建该服务,例如:Deployment、DaemonSet、Service,ConfigMap,Secret。最后,建议做成Helm Chart的方式,来发布,部署,管理。
按照这个步骤,我们之前已经了解了手动安装Nacos集群的方式,参考:手动安装Nacos集群 ,那么这里我们先了解一下Docker化的Nacos,以及如何部署在K8S环境中。
官网:https://nacos.io/
GitHub:https://github.com/alibaba/nacos
DockerHub:https://hub.docker.com/r/nacos/nacos-server
Docker:https://github.com/nacos-group/nacos-docker
Nacos On Kubernetes:https://github.com/nacos-group/nacos-k8s
环境说明:
Kubernetes 1.15.5
Nacos 1.1.4
了解Nacos Docker化
参考:
https://nacos.io/zh-cn/docs/quick-start-docker.html
https://github.com/nacos-group/nacos-docker
首先拿到Nacos的镜像为:nacos/nacos-server
,然后到Dockerhub 中找到对应的镜像,一般里面包含了使用配置说明,以及Dockerfile的GitHub。
这里我们拿到了Nacos Dockerfile的GitHub:https://www.github.com/nacos-group/nacos-docker,经查看大部分的配置都能通过环境变量的方式配置,这也是Docker化的推荐方式,下面是具体的配置项:
环境变量配置项
name
description
option
MODE
cluster模式/standalone模式
cluster/standalone default cluster
NACOS_SERVERS
nacos cluster地址
eg. ip1,ip2,ip3
PREFER_HOST_MODE
是否支持hostname
hostname/ip default ip
NACOS_SERVER_PORT
nacos服务器端口
default 8848
NACOS_SERVER_IP
多网卡下的自定义nacos服务器IP
SPRING_DATASOURCE_PLATFORM
standalone 支持 mysql
mysql / empty default empty
MYSQL_MASTER_SERVICE_HOST
mysql 主节点host地址
MYSQL_MASTER_SERVICE_PORT
mysql 主节点端口
default : 3306
MYSQL_MASTER_SERVICE_DB_NAME
mysql 主节点数据库名称
MYSQL_MASTER_SERVICE_USER
数据库用户名
MYSQL_MASTER_SERVICE_PASSWORD
数据库密码
MYSQL_SLAVE_SERVICE_HOST
mysql从节点host地址
MYSQL_SLAVE_SERVICE_PORT
mysql从节点端口
default :3306
MYSQL_DATABASE_NUM
数据库数量
default :2
JVM_XMS
-Xms
default :2g
JVM_XMX
-Xmx
default :2g
JVM_XMN
-Xmn
default :1g
JVM_MS
-XX:MetaspaceSize
default :128m
JVM_MMS
-XX:MaxMetaspaceSize
default :320m
NACOS_DEBUG
开启远程调试
y/n default :n
TOMCAT_ACCESSLOG_ENABLED
server.tomcat.accesslog.enabled
default :false
知道了Nacos 在docker中的配置方式是使用环境变量,以及具体的环境变量对应的配置,但是我们不了解是如何使用环境变量配置Nacos的,接着往下看:
找到具体的Dockerfile 文件:
https://github.com/nacos-group/nacos-docker/tree/master/build
位置:
https://github.com/nacos-group/nacos-docker/blob/master/build/Dockerfile
FROM centos:7.5 .1804 MAINTAINER pader "huangmnlove@163.com" ENV MODE="cluster" \ PREFER_HOST_MODE="ip" \ BASE_DIR="/home/nacos" \ CLASSPATH=".:/home/nacos/conf:$CLASSPATH" \ CLUSTER_CONF="/home/nacos/conf/cluster.conf" \ FUNCTION_MODE="all" \ JAVA_HOME="/usr/lib/jvm/java-1.8.0-openjdk" \ NACOS_USER="nacos" \ JAVA="/usr/lib/jvm/java-1.8.0-openjdk/bin/java" \ JVM_XMS="2g" \ JVM_XMX="2g" \ JVM_XMN="1g" \ JVM_MS="128m" \ JVM_MMS="320m" \ NACOS_DEBUG="n" \ TOMCAT_ACCESSLOG_ENABLED="false" \ TIME_ZONE="Asia/Shanghai" ARG NACOS_VERSION=1.1 .4 WORKDIR /$BASE_DIR RUN set -x \ && yum update -y \ && yum install -y java-1.8.0-openjdk java-1.8.0-openjdk-devel wget iputils nc vim libcurl\ && wget https://github.com/alibaba/nacos/releases/download/${NACOS_VERSION} /nacos-server-${NACOS_VERSION} .tar.gz -P /home \ && tar -xzvf /home/nacos-server-${NACOS_VERSION} .tar.gz -C /home \ && rm -rf /home/nacos-server-${NACOS_VERSION} .tar.gz /home/nacos/bin/* /home/nacos/conf/*.properties /home/nacos/conf/*.example /home/nacos/conf/nacos-mysql.sql \ && yum autoremove -y wget \ && ln -snf /usr/share/zoneinfo/$TIME_ZONE /etc/localtime && echo '$TIME_ZONE' > /etc/timezone \ && yum clean all ADD bin/docker-startup.sh bin/docker-startup.sh ADD conf/application.properties conf/application.properties ADD init.d/custom.properties init.d/custom.properties RUN mkdir -p logs \ && cd logs \ && touch start.out \ && ln -sf /dev/stdout start.out \ && ln -sf /dev/stderr start.out RUN chmod +x bin/docker-startup.sh EXPOSE 8848 ENTRYPOINT ["bin/docker-startup.sh" ]
其次查看bin/docker-startup.sh
启动脚本:
位置:https://github.com/nacos-group/nacos-docker/blob/master/build/bin/docker-startup.sh
#!/bin/bash set -xexport DEFAULT_SEARCH_LOCATIONS="classpath:/,classpath:/config/,file:./,file:./config/" export CUSTOM_SEARCH_LOCATIONS=${DEFAULT_SEARCH_LOCATIONS} ,file:${BASE_DIR} /conf/,${BASE_DIR} /init.d/export CUSTOM_SEARCH_NAMES="application,custom" PLUGINS_DIR="/home/nacos/plugins/peer-finder" function print_servers (){ if [[ ! -d "${PLUGINS_DIR} " ]]; then echo "" > "$CLUSTER_CONF " for server in ${NACOS_SERVERS} ; do echo "$server " >> "$CLUSTER_CONF " done else bash $PLUGINS_DIR /plugin.sh sleep 30 4fi } if [[ "${MODE} " == "standalone" ]]; then JAVA_OPT="${JAVA_OPT} -Xms512m -Xmx512m -Xmn256m" JAVA_OPT="${JAVA_OPT} -Dnacos.standalone=true" else JAVA_OPT="${JAVA_OPT} -server -Xms${JVM_XMS} -Xmx${JVM_XMX} -Xmn${JVM_XMN} -XX:MetaspaceSize=${JVM_MS} -XX:MaxMetaspaceSize=${JVM_MMS} " if [[ "${NACOS_DEBUG} " == "y" ]]; then JAVA_OPT="${JAVA_OPT} -Xdebug -Xrunjdwp:transport=dt_socket,address=9555,server=y,suspend=n" fi JAVA_OPT="${JAVA_OPT} -XX:-OmitStackTraceInFastThrow -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${BASE_DIR} /logs/java_heapdump.hprof" JAVA_OPT="${JAVA_OPT} -XX:-UseLargePages" print_servers fi if [[ "${FUNCTION_MODE} " == "config" ]]; then JAVA_OPT="${JAVA_OPT} -Dnacos.functionMode=config" elif [[ "${FUNCTION_MODE} " == "naming" ]]; then JAVA_OPT="${JAVA_OPT} -Dnacos.functionMode=naming" fi if [[ ! -z "${NACOS_SERVER_IP} " ]]; then JAVA_OPT="${JAVA_OPT} -Dnacos.server.ip=${NACOS_SERVER_IP} " fi if [[ ! -z "${USE_ONLY_SITE_INTERFACES} " ]]; then JAVA_OPT="${JAVA_OPT} -Dnacos.inetutils.use-only-site-local-interfaces=${USE_ONLY_SITE_INTERFACES} " fi if [[ ! -z "${PREFERRED_NETWORKS} " ]]; then JAVA_OPT="${JAVA_OPT} -Dnacos.inetutils.preferred-networks=${PREFERRED_NETWORKS} " fi if [[ ! -z "${IGNORED_INTERFACES} " ]]; then JAVA_OPT="${JAVA_OPT} -Dnacos.inetutils.ignored-interfaces=${IGNORED_INTERFACES} " fi if [[ "${PREFER_HOST_MODE} " == "hostname" ]]; then JAVA_OPT="${JAVA_OPT} -Dnacos.preferHostnameOverIp=true" fi JAVA_MAJOR_VERSION=$($JAVA -version 2>&1 | sed -E -n 's/.* version "([0-9]*).*$/\1/p' ) if [[ "$JAVA_MAJOR_VERSION " -ge "9" ]] ; then JAVA_OPT="${JAVA_OPT} -cp .:${BASE_DIR} /plugins/cmdb/*.jar:${BASE_DIR} /plugins/mysql/*.jar" JAVA_OPT="${JAVA_OPT} -Xlog:gc*:file=${BASE_DIR} /logs/nacos_gc.log:time,tags:filecount=10,filesize=102400" else JAVA_OPT="${JAVA_OPT} -Djava.ext.dirs=${JAVA_HOME} /jre/lib/ext:${JAVA_HOME} /lib/ext:${BASE_DIR} /plugins/cmdb:${BASE_DIR} /plugins/mysql" JAVA_OPT="${JAVA_OPT} -Xloggc:${BASE_DIR} /logs/nacos_gc.log -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M" fi JAVA_OPT="${JAVA_OPT} -Dnacos.home=${BASE_DIR} " JAVA_OPT="${JAVA_OPT} -jar ${BASE_DIR} /target/nacos-server.jar" JAVA_OPT="${JAVA_OPT} ${JAVA_OPT_EXT} " JAVA_OPT="${JAVA_OPT} --spring.config.location=${CUSTOM_SEARCH_LOCATIONS} " JAVA_OPT="${JAVA_OPT} --spring.config.name=${CUSTOM_SEARCH_NAMES} " JAVA_OPT="${JAVA_OPT} --logging.config=${BASE_DIR} /conf/nacos-logback.xml" JAVA_OPT="${JAVA_OPT} --server.max-http-header-size=524288" echo "nacos is starting,you can check the ${BASE_DIR} /logs/start.out" echo "$JAVA ${JAVA_OPT} " > ${BASE_DIR} /logs/start.out 2>&1 &nohup $JAVA ${JAVA_OPT} > ${BASE_DIR} /logs/start.out 2>&1 < /dev/null
再来看一下application.properties:
位置:
https://github.com/nacos-group/nacos-docker/blob/master/build/conf/application.properties
# spring server.servlet.contextPath=${SERVER_SERVLET_CONTEXTPATH:/nacos} server.contextPath=/nacos server.port=${NACOS_SERVER_PORT:8848} spring.datasource.platform=${SPRING_DATASOURCE_PLATFORM:""} nacos.cmdb.dumpTaskInterval=3600 nacos.cmdb.eventTaskInterval=10 nacos.cmdb.labelTaskInterval=300 nacos.cmdb.loadDataAtStart=false db.num=${MYSQL_DATABASE_NUM:2} db.url.0=jdbc:mysql://${MYSQL_MASTER_SERVICE_HOST}:${MYSQL_MASTER_SERVICE_PORT:3306}/${MYSQL_MASTER_SERVICE_DB_NAME}?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true db.url.1=jdbc:mysql://${MYSQL_SLAVE_SERVICE_HOST}:${MYSQL_SLAVE_SERVICE_PORT:3306}/${MYSQL_MASTER_SERVICE_DB_NAME}?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true db.user=${MYSQL_MASTER_SERVICE_USER} db.password=${MYSQL_MASTER_SERVICE_PASSWORD} server.tomcat.accesslog.enabled=${TOMCAT_ACCESSLOG_ENABLED:false} server.tomcat.accesslog.pattern=%h %l %u %t "%r" %s %b %D # default current work dir server.tomcat.basedir= ## spring security config ### turn off security nacos.security.ignore.urls=/,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-fe/public/**,/v1/auth/login,/v1/console/health/**,/v1/cs/**,/v1/ns/**,/v1/cmdb/**,/actuator/**,/v1/console/server/** # metrics for elastic search management.metrics.export.elastic.enabled=false management.metrics.export.influx.enabled=false nacos.naming.distro.taskDispatchThreadCount=10 nacos.naming.distro.taskDispatchPeriod=200 nacos.naming.distro.batchSyncKeyCount=1000 nacos.naming.distro.initDataRatio=0.9 nacos.naming.distro.syncRetryDelay=5000 nacos.naming.data.warmup=true
这里就是如何通过环境变量的方式配置Nacos的啦,如果变量名为空,那么将使用冒号后面的默认值。
你还记得BASH中如何设置成这种效果嘛?
$ echo ${name} $ echo ${name:-NAME} NAME $ echo ${name} $ echo ${name} $ echo ${name:=NAME} NAME ~$ echo ${name} NAME $ echo ${age} $ echo ${age:?AGE NULL} -bash: age: AGE NULL $ echo ${age:?} -bash: age: parameter null or not set $ age='' $ echo ${age:?} -bash: age: parameter null or not set $ age=22 $ echo ${age:?} 22 $ echo ${sex:+3} $ sex=1 $ echo ${sex:+3} 3 $ echo ${sex} 1
好了,Nacos如何实现Docker化的我们大概了解了,下面就是如何在Kubernetes安装Docker化的Nacos。
在Kubernetes环境下安装Nacos集群
参考:
https://nacos.io/zh-cn/docs/use-nacos-with-kubernetes.html
https://github.com/nacos-group/nacos-k8s/tree/master/deploy/nacos
这里我们是用nfs-client-provisioner
来提供持久化,关于nfs-client-provisioner
的安装请参考:在Kubernetes上安装nfs-client-provisioner来提供StorageClass
修改基础文件:
$ wget -c "https://github.com/nacos-group/nacos-k8s/raw/master/deploy/nacos/nacos-pvc-nfs.yaml"
YAML 修改成如下:
$ cat nacos-pvc-nfs.yaml --- apiVersion: v1 kind: Service metadata: name: nacos-headless labels: app: nacos annotations: service.alpha.kubernetes.io/tolerate-unready-endpoints: "true" spec: ports: - port: 8848 name: server targetPort: 8848 clusterIP: None selector: app: nacos --- apiVersion: v1 kind: ConfigMap metadata: name: nacos-cm data: spring.datasource.platform: "mysql" mysql.database.num: "1" mysql.master.host: "x.x.x.x" mysql.master.db.name: "nacos" mysql.master.port: "3306" mysql.master.user: "nacos" mysql.master.password: "nacos-password" nacos_server_port: "8848" prefer_host_mode: "hostname" nacos_servers: "nacos-0.nacos-headless.default.svc.cluster.local:8848 nacos-1.nacos-headless.default.svc.cluster.local:8848 nacos-2.nacos-headless.default.svc.cluster.local:8848" --- apiVersion: apps/v1 kind: StatefulSet metadata: name: nacos spec: serviceName: nacos-headless replicas: 3 template: metadata: labels: app: nacos annotations: pod.alpha.kubernetes.io/initialized: "true" spec: affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: "app" operator: In values: - nacos topologyKey: "kubernetes.io/hostname" containers: - name: nacos imagePullPolicy: IfNotPresent image: nacos/nacos-server:1.1.4 resources: requests: memory: "2Gi" cpu: "100m" limits: memory: "2Gi" cpu: "300m" ports: - containerPort: 8848 name: client-port env: - name: NACOS_REPLICAS value: "3" - name: SERVICE_NAME value: "nacos-headless" - name: POD_NAMESPACE valueFrom: fieldRef: apiVersion: v1 fieldPath: metadata.namespace - name: SPRING_DATASOURCE_PLATFORM valueFrom: configMapKeyRef: name: nacos-cm key: spring.datasource.platform - name: MYSQL_MASTER_SERVICE_HOST valueFrom: configMapKeyRef: name: nacos-cm key: mysql.master.host - name: MYSQL_MASTER_SERVICE_DB_NAME valueFrom: configMapKeyRef: name: nacos-cm key: mysql.master.db.name - name: MYSQL_MASTER_SERVICE_PORT valueFrom: configMapKeyRef: name: nacos-cm key: mysql.master.port - name: MYSQL_DATABASE_NUM valueFrom: configMapKeyRef: name: nacos-cm key: mysql.database.num - name: MYSQL_MASTER_SERVICE_USER valueFrom: configMapKeyRef: name: nacos-cm key: mysql.master.user - name: MYSQL_MASTER_SERVICE_PASSWORD valueFrom: configMapKeyRef: name: nacos-cm key: mysql.master.password - name: JVM_XMS_NUM valueFrom: resourceFieldRef: divisor: 1Gi resource: requests.memory - name: JVM_XMS value: $(JVM_XMS_NUM)g - name: JVM_XMX_NUM valueFrom: resourceFieldRef: divisor: 1Gi resource: limits.memory - name: JVM_XMX value: $(JVM_XMX_NUM)g - name: JVM_XMN value: 1g - name: NACOS_SERVER_PORT valueFrom: configMapKeyRef: name: nacos-cm key: nacos_server_port - name: PREFER_HOST_MODE valueFrom: configMapKeyRef: name: nacos-cm key: prefer_host_mode - name: NACOS_SERVERS valueFrom: configMapKeyRef: name: nacos-cm key: nacos_servers readinessProbe: httpGet: port: client-port path: /nacos/v1/console/health/readiness initialDelaySeconds: 90 timeoutSeconds: 3 livenessProbe: httpGet: port: client-port path: /nacos/v1/console/health/liveness initialDelaySeconds: 90 timeoutSeconds: 3 volumeMounts: - name: datadir mountPath: /home/nacos/data - name: logdir mountPath: /home/nacos/logs volumeClaimTemplates: - metadata: name: datadir spec: storageClassName: nfs-client accessModes: [ "ReadWriteMany" ] resources: requests: storage: 1Gi - metadata: name: logdir spec: storageClassName: nfs-client accessModes: [ "ReadWriteMany" ] resources: requests: storage: 1Gi selector: matchLabels: app: nacos --- apiVersion: extensions/v1beta1 kind: Ingress metadata: name: nacos annotations: kubernetes.io/ingress.class: "nginx" spec: rules: - host: nacos.test.aws.test.com http: paths: - path: /nacos backend: serviceName: nacos-headless servicePort: server
修改说明:
没有使用官方的initContainers
的nacos/nacos-peer-finder-plugin:latest
,经测试启动正常,也能看到页面,但是,一直无法查看到集群主机列表,一直提示:server is STARTING now, please try again later!
,所有的API接口也提示这个。
所以直接通过环境变量指定了所有的Nacos Cluster 节点的地址。
使用resource中的资源充当-Xms,-Xmx
,但是-Xmn
,需要手动指定。
将环境变量的值,都从configmap获取。
带来的问题:扩缩容比较麻烦
应用yaml:
$ kubectl apply -f nacos-pvc-nfs.yaml
然后配置域名解析nacos.test.aws.test.com
指定到nginx-ingress-controller的公网地址。
访问nacos.test.aws.test.com
,查看集群节点列表:
注意:这里只是映射了Nacos的Dashboard,但是如果开发人员需要通过公网使用Nacos呢?
这里使用nginx-ingress-controller的TCP转发功能:
首先:确认nginx-ingress-controller参数中使用的TCP的configmap是哪个?
如果是通过Helm安装的话:在values.yaml如果tcp和udp的配置是空的,那么默认不会添加这两个参数的:--tcp-services-configmap
和--udp-services-configmap
建议通过Helm update进行升级。
containers: - args: - /nginx-ingress-controller - --default-backend-service=kube-system/nginx-ingress-default-backend - --election-id=ingress-controller-leader - --ingress-class=nginx - --configmap=kube-system/nginx-ingress-controller - --tcp-services-configmap=kube-system/nginx-ingress-tcp - --udp-services-configmap=kube-system/nginx-ingress-udp
我们来编辑这个configMap:
$ kubectl -n kube-system edit cm nginx-ingress-tcp apiVersion: v1 data: "2181": default/zookeeper:2181 "8848": default/nacos-headless:8848 kind: ConfigMap metadata: creationTimestamp: "2019-11-27T08:58:01Z" labels: app: nginx-ingress chart: nginx-ingress-1.6.0 component: controller heritage: Tiller release: dev-microoak-cn-ingress name: nginx-ingress-tcp namespace: kube-system resourceVersion: "96042220" selfLink: /api/v1/namespaces/kube-system/configmaps/nginx-ingress-tcp uid: 04158536 -10f4-11ea-9238-0296672f1eaa
在data下添加:
"8848": microoak/nacos-headless:8848
格式如下:
PORT: <namespace>/<service name>:<service port> PORT 为nginx-ingress-controller监听的端口,并将流量转发到后端 <namespace> 为nginx-ingress-controller将流量转发到的后端所在的namespace <service name> 为nginx-ingress-controller将流量转发到的后端的service name,这里是nacos-headless <service port> 为nginx-ingress-controller将流量转发到的后端的service port,这里是8848
然后就可以通过:
<nginx-ingress-controller IP>:PORT 访问了;
如果nginx-ingress-controller有多个,最好前边再加个LB。通过访问LB IP+LB PORT的方式访问。
本文到这里就结束了,欢迎期待后面的文章。您可以关注下方的公众号二维码,在第一时间查看新文章。