由于近期换了工作,新公司这边主业务也是使用k8s来跑服务;由于使用go语言进行开发,故这边之前就选择采用etcd仅作选举使用。
最近开发的新的服务模块,需要使用到etcd的服务发现功能,再使用之前运行的etcd时就出现了问题。
问题主要有两个:
- 原镜像启动参数问题,导致使用服务发现方式连接etcd节点出现问题;但仅使用选举功能不受影响
- 开发代码配置问题,导致发现方连接不到服务方地址
第一个问题是这样,启用参数配置错误,导致程序连接不到 advertise-client 地址,启动YAML命令:
官方对于启动参数的解释:
知道原因了就可以解决问题,修改启动参数即可;但k8s中从环境变量env.status.podIP中提取到的POD运行时产生的随机IP是不能直接作用于与其同级的 command 中的,于是我就重新制作了运行镜像,和类型为Deployment的yaml文件。
制作镜像采用了官方CentOS的基础镜像和etcd 3.5正式版的二进程文件,使用自建脚本进行启动:
vim start-etcd.sh
#!/bin/bash # Author:Chris __On 2021/08/22 # =====================Description===================== # [Features]: This is for Start an Singel ETCD in Docker Container. # ===================================================== # <----------------------------Configure Start---------------------------> Base=$(cd `dirname ${BASH_SOURCE}` ; pwd) Execute="/usr/local/bin/etcd" IP=$(ip add | grep inet | grep -v 127 | awk '{print $2}' | cut -d / -f 1) [ -z "${POD_IP}" ] && POD_IP=${IP} Name=${INS_NAME} Cluster_List=${cluster_list:-"${Name}=http://${POD_IP}:2380"} Cluster_Tk=${cluster_token:-"etcd-singel"} Start_Opts="--name=${Name} --listen-client-urls=http://0.0.0.0:2379 --listen-peer-urls=http://0.0.0.0:2380 --advertise-client-urls=http://${POD_IP}:2379 --initial-advertise-peer-urls=http://${POD_IP}:2380 --initial-cluster=${Cluster_List} --initial-cluster-token=${Cluster_Tk} --initial-cluster-state=new --data-dir=/var/lib/etcd" Ext_Args="$@" # <----------------------------Configure End----------------------------> if [ ! -f "${Execute}" ];then echo "ERROR: Can not find execute file: ${Execute}." exit 1 fi # 使用exec command, 会用 command 进程替换当前shell进程, 并且保持 PID 不变。 # 为保证Docker容器不会终止, 脚本需一直处于运行状态, # 故不要在最后添加 & 让java在后台另起进程运行, 而是直接替代当前脚本运行。 # Tips: docker logs显示容器内/dev/stdout, /dev/stderr的内容, 阿里云k8s也是收集此日志; # 故运行时就不进行日志重定向($App_Log)及 2>&1 了 exec ${Execute} ${Start_Opts} ${Ext_Args}
Dockerfile文件:
vim Dockerfile
FROM centos as build RUN sed -i "/^alias mv/a\alias ll='ls -lh --time-style=\"+%Y/%m/%d %H:%M\" --color'" ~/.bashrc ADD etcd-v3.5.0-linux-amd64/* /usr/local/bin/ ADD start-etcd.sh /root/ RUN yum install -y net-tools && yum clean all RUN mkdir -p /var/lib/etcd /etc/etcd RUN rm -f /root/*.cfg /root/*.log FROM scratch COPY --from=build / . LABEL maintainer="Chris" EXPOSE 2379 2380 WORKDIR /root ENTRYPOINT ["/root/start-etcd.sh"]
打包镜像:
docker build -t etcd:v3.5.0-c8 .
打包完成后重新 tag 下,然后上传到k8s群集可以访问到的镜像仓库即可。
程序yaml文件:
apiVersion: apps/v1 kind: Deployment metadata: labels: app: myetcd name: myetcd namespace: myetcd spec: progressDeadlineSeconds: 600 replicas: 1 selector: matchLabels: app: myetcd strategy: rollingUpdate: maxSurge: 25% maxUnavailable: 25% type: RollingUpdate template: metadata: labels: app: myetcd spec: containers: - env: - name: POD_IP valueFrom: fieldRef: fieldPath: status.podIP - name: INS_NAME value: s1 - name: cluster_list value: "" - name: cluster_token value: etcd-singel args: - "--host-whitelist=*" image: 'registry-vpc.cn-xx.aliyuncs.com/xxx/etcd:v3.5.0-c8' imagePullPolicy: IfNotPresent name: myetcd ports: - containerPort: 2379 name: p2379 protocol: TCP - containerPort: 2380 name: p2380 protocol: TCP resources: requests: cpu: 250m memory: 512Mi volumeMounts: - mountPath: /etc/localtime name: volume-localtime restartPolicy: Always terminationGracePeriodSeconds: 30 volumes: - hostPath: path: /etc/localtime type: '' name: volume-localtime
服务yaml文件:
apiVersion: v1 kind: Service metadata: name: myetcd-svc namespace: myetcd spec: ports: - name: p2379 port: 2379 protocol: TCP targetPort: 2379 - name: p2380 port: 2380 protocol: TCP targetPort: 2380 selector: app: myetcd type: ClusterIP
这样群集中便可使用 myetcd-svc.myetcd:2379 来访问到 etcd 程序,再通过它拿到advertise-client地址来连接。
Tips:我是根据之前样式并且也没有数据需要存储,就顺手制作成 Deployment 进行启动,你也可以制作成StatefulSet来持久化 /var/lib/etcd 下的数据。只是当Pod销毁后,重启启动的 Pod 又分重新分配到不同的 ip 地址,此时用来做服务发现的程序也需要重启进行重新连接,故若十分依赖 etcd 的话建议在 k8s 群集之外在有固定IP的主机上以群集方式运行。
第二个遇到的问题就是 go 程序配置的问题了,服务被发现端在etcd提供的值地址是服务发现端所无法连接的。
由于配置里固定了地址为 127.0.0.1:8080 ,导致发现端pod是连不上被发现端的pod的。
和开发说明后,改为 0.0.0.0 即可正常:
此次遇到的问题主要还是配置,无论是基础服务配置还是程序服务配置,故大家也多留意下配置。