如何在Kubernetes清单文件中动态获取Service的外部IP
动态获取跨命名空间Internal LoadBalancer Service IP的可行方案
针对你的需求,下面提供几种无需手动硬编码IP的实现方式,优先推荐使用DNS名称的方案,这是Kubernetes原生服务发现机制,最稳定省心:
方案1:使用Service跨命名空间DNS名称(优先推荐)
Kubernetes内置DNS服务支持跨命名空间的Service解析,格式为 {服务名}.{命名空间}.svc.cluster.local。你的目标Service是app(位于app命名空间),直接用这个DNS名称替代IP即可,无需依赖任何外部工具:
修改Deployment容器的启动命令,把硬编码的IP替换为DNS地址:
apiVersion: apps/v1 kind: Deployment metadata: name: app-api namespace: app-api spec: selector: matchLabels: app: app-api replicas: 1 template: metadata: labels: app: app-api spec: containers: - name: app-api image: asia-south2-docker.pkg.dev/rnd20/app-api/api:09 # 用DNS名称替代硬编码IP command: ["java","-jar","-Dallow.only.apigateway.request=false","-Dserver.port=8084","-Ddedupe.searcher.url=http://app.app.svc.cluster.local:80","-Dspring.cloud.zookeeper.connect-string=app.app.svc.cluster.local:2181","-Dlogging$.file.path=/usr/src/app/logs/springboot","/usr/src/app/app_api/dedupe-engine-components.jar",">","/usr/src/app/out.log"] # 其余配置保持不变...
这种方式完全由Kubernetes维护解析关系,Service IP变化时自动更新,无需额外维护。
方案2:通过ConfigMap定时同步Service IP(必须用LB IP时)
如果业务强制要求使用Internal LoadBalancer的外部IP,可以通过CronJob定时同步IP到ConfigMap,再注入到Deployment的环境变量中:
1. 创建存储IP的ConfigMap
apiVersion: v1 kind: ConfigMap metadata: name: app-service-ip namespace: app-api data: APP_IP: ""
2. 创建CronJob定期更新ConfigMap
先给执行任务的ServiceAccount配置RBAC权限(需要读取app命名空间的Service,修改app-api命名空间的ConfigMap):
# ServiceAccount apiVersion: v1 kind: ServiceAccount metadata: name: app-api-sa namespace: app-api --- # 读取跨命名空间Service的ClusterRole apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: app-service-reader rules: - apiGroups: [""] resources: ["services"] verbs: ["get"] resourceNames: ["app"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: app-api-sa-binding subjects: - kind: ServiceAccount name: app-api-sa namespace: app-api roleRef: kind: ClusterRole name: app-service-reader apiGroup: rbac.authorization.k8s.io --- # 修改ConfigMap的Role apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: configmap-updater namespace: app-api rules: - apiGroups: [""] resources: ["configmaps"] verbs: ["patch"] resourceNames: ["app-service-ip"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: app-api-sa-configmap-binding namespace: app-api subjects: - kind: ServiceAccount name: app-api-sa roleRef: kind: Role name: configmap-updater apiGroup: rbac.authorization.k8s.io
然后创建CronJob(每5分钟更新一次IP):
apiVersion: batch/v1 kind: CronJob metadata: name: update-app-ip namespace: app-api spec: schedule: "*/5 * * * *" jobTemplate: spec: template: spec: serviceAccountName: app-api-sa containers: - name: update-ip image: bitnami/kubectl:latest command: ["bash", "-c", "APP_IP=$(kubectl get service app -n app -o jsonpath='{.status.loadBalancer.ingress[0].ip}'); kubectl patch configmap app-service-ip -n app-api -p '{\"data\":{\"APP_IP\":\"$APP_IP\"}}'"] restartPolicy: OnFailure
3. 修改Deployment注入环境变量
apiVersion: apps/v1 kind: Deployment metadata: name: app-api namespace: app-api spec: selector: matchLabels: app: app-api replicas: 1 template: metadata: labels: app: app-api spec: containers: - name: app-api image: asia-south2-docker.pkg.dev/rnd20/app-api/api:09 env: - name: APP_SERVICE_IP valueFrom: configMapKeyRef: name: app-service-ip key: APP_IP # 通过环境变量引用动态IP command: ["bash", "-c", "java -jar -Dallow.only.apigateway.request=false -Dserver.port=8084 -Ddedupe.searcher.url=http://$APP_SERVICE_IP:80 -Dspring.cloud.zookeeper.connect-string=$APP_SERVICE_IP:2181 -Dlogging$.file.path=/usr/src/app/logs/springboot /usr/src/app/app_api/dedupe-engine-components.jar > /usr/src/app/out.log"] # 其余配置保持不变...
注意:Service IP变化后,需要手动重启Deployment的Pod才能生效,也可以使用Reloader工具自动触发Pod重启。
方案3:用Init容器启动前获取IP
如果只需要在Pod启动时获取一次IP,可以添加Init容器提前查询并写入共享卷,主容器读取后构造启动命令:
apiVersion: apps/v1 kind: Deployment metadata: name: app-api namespace: app-api spec: selector: matchLabels: app: app-api replicas: 1 template: metadata: labels: app: app-api spec: volumes: - name: service-ip-volume emptyDir: {} # 提前获取Service IP的Init容器 initContainers: - name: get-app-ip image: bitnami/kubectl:latest command: ["bash", "-c", "kubectl get service app -n app -o jsonpath='{.status.loadBalancer.ingress[0].ip}' > /service-ip/app_ip.txt"] volumeMounts: - name: service-ip-volume mountPath: /service-ip serviceAccountName: app-api-sa # 需要方案2中的RBAC权限 containers: - name: app-api image: asia-south2-docker.pkg.dev/rnd20/app-api/api:09 volumeMounts: - name: service-ip-volume mountPath: /service-ip # 读取共享卷中的IP构造命令 command: ["bash", "-c", "APP_IP=$(cat /service-ip/app_ip.txt); java -jar -Dallow.only.apigateway.request=false -Dserver.port=8084 -Ddedupe.searcher.url=http://$APP_IP:80 -Dspring.cloud.zookeeper.connect-string=$APP_IP:2181 -Dlogging$.file.path=/usr/src/app/logs/springboot /usr/src/app/app_api/dedupe-engine-components.jar > /usr/src/app/out.log"] # 其余配置保持不变...
这种方式适合IP不频繁变化的场景,IP更新后需要重启Pod才能生效。
内容的提问来源于stack exchange,提问作者Nitin G
相关产品推荐
相关产品推荐

