背景

在推动业务上容器过程中,存在业务方框架(如Java的dubbo)对ip依赖较重,但框架改造周期较长的问题。为了解决这个问题,运维侧从网络层面固定容器IP的方式着手,引入了腾讯开源的Galaxy插件。这里对此插件的安装部署进行说明。

Galaxy架构概览


Galaxy网络方案主要包括两个模块:

  • galaxy:以daemonset形式存在每个k8s集群的节点上,它通过判断pod annotation信息,来设定pod网络是用固定ip还是非固定ip
  • galaxy-ipam:根据pod的生命周期,完成pod ip的分配、释放、已分配ip信息的记录等功能

配置部署

预备环境

已有K8S集群环境

组件名 版本
kube各组件 1.16.4
docker 19.03.5

Galaxy方案的落地,需要结合cni插件一起来完成。Galaxy支持多种cni插件,包括flannel、SRIOV、vlan等,这里我们选择vlan的方式。

因此,每个k8s集群节点上需要安装kubernete-cni

yum install -y kubernetes-cni

注意:
执行以上操作之后,由于kubernetes-cni依赖于kubelet,导致其自动安装了最新版本的kubelet,将我们原本1.16.4的kubelet覆盖,所以需要做以下回退操作:rpm -e kubelet --nodeps && yum install -y kubelet-1.16.4

镜像准备

部署过程中,Galaxy网络方案的两个模块都是以容器方式运行的,因此我们先定制镜像,推送到我们的私有容器仓库。我们在部署使用的时候,当时galaxy最新版是v1.0.2,这里也以此版本来进行部署说明。

1. 下载镜像

我们需要的是:tkestack/galaxy:v1.0.2tkestack/galaxy-ipam:v1.0.2两个镜像。

由于国内下载速度感人,大家可以想办法用其他代理方式进行下载,这里就不多说了。

2. 定制镜像

下载的镜像时区并不是北京时间的,可以采用两种方式解决:

  • 方法一:每次使用镜像时,在yaml加上挂载宿主机/etc/localtime的配置
  • 方法二:直接修改原镜像中的/etc/localtime为/usr/share/zoneinfo/Asia/Shanghai,一劳永逸

个人倾向方法二,这里以galaxy:v1.0.2镜像制作为例进行说明(假设,私用仓库地址为:myhub.example.com/op-base)。

修改时区的Dockerfile如下:

FROM tkestack/galaxy:v1.0.2RUN rm -f /etc/localtime \&& ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

在Dockerfile文件所在目录,执行build操作:

docker build -t myhub.example.com/op-base/galaxy:v1.0.2 .

将镜像推送到我们的私有Harbor仓库(推送需要账号权限,需先docker login):

docker push myhub.example.com/op-base/galaxy:v1.0.2

配置部署galaxy模块

在Galaxy项目https://github.com/tkestack/galaxy/tree/master/yaml路径下有我们需要的yaml配置文件:

将其下载到有kubectl的节点,但是这些yaml有些地方需要修改。

1 运行galaxy的daemonset

配置部署galaxy模块,使用的是galaxy.yaml,有两处需要修改

(1)修改镜像和启动参数

......imagePullSecrets:- name: myhubcontainers:- image: myhub.example.com/op-base/galaxy:v1.0.2command: ["/bin/sh"]# qcloud galaxy should run with --route-eni#  args: ["-c", "cp -p /etc/galaxy/cni/00-galaxy.conf /etc/cni/net.d/; cp -p /opt/cni/galaxy/bin/galaxy-sdn /opt/cni/galaxy/bin/loopback /opt/cni/bin/; /usr/bin/galaxy --logtostderr=true --v=3 --route-eni"]# private-cloud should run without --route-eniargs: ["-c", "cp -p /etc/galaxy/cni/00-galaxy.conf /etc/cni/net.d/; cp -p /opt/cni/galaxy/bin/galaxy-sdn /opt/cni/galaxy/bin/loopback /opt/cni/bin/; /usr/bin/galaxy --logtostderr=true --v=3"]
......

说明:

  • 修改image为我们自定义的镜像myhub.example.com/op-base/galaxy:v1.0.2
  • 指定从私有仓库拉取镜像所需的secrets:imagePullSecrets配置为name: myhub (这里根据自己实际情况而定)
  • 部署环境为自建机房,不是腾讯云,所以这里启动参数使用不带--route-eni

(2)修改galaxy的网络配置
我们的诉求是:在一个K8S集群上,pod需要既能配置不使用固定ip,也可以配置使用固定ip。

即,在加上指定annotation参数时才使用固定ip方式配置pod网络,默认情况下,不用固定ip。
因此,我们采用bridge+vlan的两种网络方式:
默认情况下,走bridge网络,不会固定网络ip;
当识别带有

......
apiVersion: v1
kind: ConfigMap
metadata:name: galaxy-etcnamespace: kube-system
data:# update network card name in "galaxy-k8s-vlan" and "galaxy-k8s-sriov" if necessary# update vf_num in "galaxy-k8s-sriov" according to demandgalaxy.json: |{"NetworkConf":[{"name":"tke-route-eni","type":"tke-route-eni","eni":"eth1","routeTable":1},{"name":"galaxy-flannel","type":"galaxy-flannel", "delegate":{"type":"galaxy-veth"},"subnetFile":"/run/flannel/subnet.env"},{"name":"galaxy-k8s-vlan","type":"galaxy-k8s-vlan", "device":"eth0"},{"name":"galaxy-k8s-sriov","type": "galaxy-k8s-sriov", "device": "eth1", "vf_num": 10}],"DefaultNetworks": ["my-bridge"],"ENIIPNetwork": "galaxy-k8s-vlan"}
......

说明:

  • DefaultNetworks指定为使用bridge方式,这里取名为my-bridge (这个名字需要跟服务器节点上cni配置中的bridge名一致)
  • device指定服务器的网卡名为eth0 (网卡名根据实际情况来修改)

除了上面两处修改外,别忘了添加cni的bridge配置

# cat /etc/cni/net.d/10-my-bridge.conf
{"cniVersion": "0.2.0","name": "my-bridge","type": "bridge","bridge": "cbr0","addIf": "eth0","isGateway": true, "ipMasq": false,"ipam": {"type": "host-local","ranges": [[{"subnet": "10.20.30.0/26" }]],"routes": [{ "dst": "0.0.0.0/0" }]}
}

最后,执行如下命令就可以将galaxy的daemonset运行起来:

kubectl apply -f galaxy.yaml

运行成功后,在集群节点上会发现:

  • /opt/cni/bin/目录下多了galaxy-sdnloopback两个二进制文件;
  • /etc/cni/net.d/目录下生成了一个00-galaxy.conf配置文件,内容如下:
{"type": "galaxy-sdn","capabilities": {"portMappings": true},"cniVersion": "0.2.0"
}

注意:之所以将bridge配置文件10-my-bridge.conf取名为10-前缀,是为了让其排在00-前缀的00-galaxy.conf文件后面被加载,不然会出现奇怪的问题。

2 配置kubelet支持cni网络插件

在kubelet的启动脚本里加上--network-plugin=cni --cni-bin-dir=/opt/cni/bin/参数,然后重启kubelet。

kubelet的完整启动脚本内容类似如下:

# /usr/lib/systemd/system/kubelet.service
[Unit]
Description=kubelet: The Kubernetes Node Agent
Documentation=https://kubernetes.io/docs/[Service]
ExecStart=/usr/bin/kubelet \--eviction-hard=memory.available<1024Mi,nodefs.available<10%,nodefs.inodesFree<5% \--system-reserved=cpu=1,memory=1G \--kube-reserved=cpu=1,memory=1G \--cgroups-per-qos=true \--address={{your_node_ip}} \--hostname-override={{your_node_ip}} \--cgroup-driver=systemd \--pod-infra-container-image=myhub.example.com/kubernetes/pause-amd64:3.1 \--experimental-bootstrap-kubeconfig=/etc/kubernetes/bootstrap.conf \--kubeconfig=/etc/kubernetes/kubelet.conf \--cert-dir=/etc/kubernetes/pki \--cluster-dns={{your_dns_ip}} \--cluster-domain={{your_domain_postfix}}. \--network-plugin=cni \--cni-bin-dir=/opt/cni/bin/ \--hairpin-mode=promiscuous-bridge \--fail-swap-on=false \--feature-gates=RotateKubeletServerCertificate=true,RotateKubeletClientCertificate=true \--rotate-certificates \--serialize-image-pulls=false \--max-pods=60 \--logtostderr=true \--v=2
Restart=always
StartLimitInterval=0
RestartSec=5[Install]
WantedBy=multi-user.target

配置部署galaxy-ipam模块

1. 配置floatingip-config

假设:
k8s节点所属ip网段为:10.10.100.0/24
容器可用ip范围为:10.11.128.1~10.11.135.253
容器ip所属网段为:10.11.128.0/21
容器的网关ip为:10.11.135.254
vlan的id为:1200

注:这些网络信息,实际通常需要网络组同事帮忙分配确定

以ConfigMap的方式配置,这里创建floatingip-config.yaml配置文件,内容如下:

kind: ConfigMap
apiVersion: v1
metadata:name: floatingip-confignamespace: kube-system
data:floatingips: '[{"routableSubnet":"10.10.100.0/24","ips":["10.11.128.1~10.11.135.253"],"subnet":"10.11.128.0/21","gateway":"10.11.135.254","vlan":1200}]'

说明:

  • routableSubnet:指定kubelet节点所在网段
  • ips:指定为容器ip分配的地址范围
  • subnet:容器ip的网段
  • gateway:容器地址分配的网关
  • vlan:是用来指定容器ip的vlan id,当容器ip和节点ip不属于同一个vlan时需要配置(id为数值类型,写的时候不要带引号)

floatingip-config.yaml创建完后,执行以下命令生效:

kubectl apply -f floatingip-config.yaml

2 修改galaxy-ipam.yaml配置文件

(1)修改镜像

......imagePullSecrets:- name: myhubcontainers:- image: myhub.example.com/op-base/galaxy-ipam:v1.0.2
......

说明:

  • 修改image为自定义镜像myhub.example.com/op-base/galaxy-ipam:v1.0.2
  • 指定从私有仓库拉取镜像所需的secrets:imagePullSecrets配置为name: myhub (这里根据自己实际情况而定)

(2)修改galaxy-ipam-etc配置

......
apiVersion: v1
kind: ConfigMap
metadata:name: galaxy-ipam-etcnamespace: kube-system
data:# delete cloudProviderGrpcAddr if not ENIgalaxy-ipam.json: |{"schedule_plugin": {"storageDriver": "k8s-crd","cloudProviderGrpcAddr": "127.0.0.2:80"  # 删除此行}}
......

说明:

  • 由于我们是自建IDC环境,删除"cloudProviderGrpcAddr": "127.0.0.2:80"此行配置

修改完后,执行以下命令生效:

kubectl apply -f galaxy-ipam.yaml

3 配置kube-scheduler

(1)首先配置scheduler-policy.yaml:

# make sue --policy-configmap=scheduler-policy of kube-scheduler is set
# note that --policy-config-file and --use-legacy-policy-config is conflict with --policy-configmap
apiVersion: v1
kind: ConfigMap
metadata:name: scheduler-policynamespace: kube-system
data:# set "ignoredByScheduler" to true if not ENIpolicy.cfg: |{"kind": "Policy","apiVersion": "v1","extenders": [{"urlPrefix": "http://10.20.30.40:9040/v1","httpTimeout": 70000000000,"filterVerb": "filter","BindVerb": "bind","weight": 1,"enableHttps": false,"managedResources": [{"name": "tke.cloud.tencent.com/eni-ip","ignoredByScheduler": true}]}]}

说明:

  • urlPrefix这里指定的地址是galaxy-ipam的svc的CLUSTER-IP(可以通过kubectl get svc -n kube-system查看)
  • ignoredByScheduler的说明是这样的If you want to limit each node's max Float IPs, please set ignoredByScheduler to false, then the Float IP resource will be judge by scheduler's PodFitsResource algorithm.。这里没有太理解它的意思,由于我们是自建IDC环境,按照注释提示,应该设为true

(2)配置kube-scheduler的启动脚本
在kube-scheduler的启动脚本里添加参数:--policy-configmap=scheduler-policy,然后重启kube-scheduler

注意:要确保kube-scheduler有访问configmap的权限,否则会有类似如下的报错:

system:kube-scheduler添加configmaps权限最直接的方法就是执行如下命令进入编辑:

kubectl edit clusterrole system:kube-scheduler -o yaml

然后添加:

- apiGroups:- ""resources:- configmapsverbs:- get- list- watch- update- create- patch

之后再查看已经有了configmaps权限:

kubectl describe clusterrole system:kube-scheduler


这时再执行systemctl restart kube-scheduler重启即可。

如何让pod配置使用固定ip

当galaxy和galaxy-ipam模块按上述步骤配置完成后,配置一个示例验证一下固定ip的功能是否实现

创建一个test-busybox.yaml

apiVersion: apps/v1
kind: Deployment
metadata:name: test-busybox
spec:replicas: 3selector:matchLabels:name: test-busyboxtemplate:metadata:labels:tag: lxcfsname: test-busyboxannotations:k8s.v1.cni.cncf.io/networks: "galaxy-k8s-vlan"k8s.v1.cni.galaxy.io/release-policy: "never"spec:tolerations:- operator: "Exists"containers:- name: test-busyboximage: busyboxcommand:- sleep- "3600"resources:requests:cpu: "0.1"memory: "32Mi"tke.cloud.tencent.com/eni-ip: "1"limits:cpu: "0.1"memory: "32Mi"tke.cloud.tencent.com/eni-ip: "1"

说明:

  • annotations配置:

    • k8s.v1.cni.cncf.io/networks: "galaxy-k8s-vlan":指明使用的网络类型为galaxy-k8s-vlan
    • k8s.v1.cni.galaxy.io/release-policy: "never":指明ip的释放策略,有neverimmutable两种
      • never: Never Release IP even if the Deployment or Statefulset is deleted. Submitting a same name Deployment or Statefulset will reuse previous reserved IPs.

      • immutable: Release IP Only when deleting or scaling down Deployment or Statefulset. If POD float onto a new node in case of original Node became NotReady, it will get the previous IP.

    注: 在跟galaxy开发者交流时,他建议使用never参数,immutable可能在后面的迭代中被废弃掉。

  • resources配置:

    • requestslimits属性都要添加tke.cloud.tencent.com/eni-ip: "1"

      • 不配置的话,会报如下错误:fail to establish network map[]:neither ipInfo from cni args nor ipam type from netconf

通过删除一个正在Running的pod,然后会发现再被创建出来的pod使用的ip和被删除时的ip一样,这便达到了我们固定ip的目的。

v1.0.2版本galaxy存在的问题

经过我们实际使用测试,发现v1.0.2版本存在两个问题:

  • 多vlan支持: 当有多个vlan时,一个vlan中的ip分配完之后,不会自动分配下一个vlan的ip,而是pending
  • svc问题:启用了固定ip的pod访问集群任意的svc地址都不通

对于第一个问题,我们使用一个vlan,然后在交换机层面用vxlan来隔离来避开了。
对于第二个问题,由于我们业务应用暂时没有访问svc的场景,所以也暂时不影响使用。

目前,galaxy已更新到了v1.0.3版本,新版本中已经解决了上述两个问题。

Galaxy固定容器IP网路方案相关推荐

  1. docker-compose 固定容器IP地址

    写在前面 构建微服务的时候需要固定容器的ip,防止后期重启后ip变动. 本来说在portainer里面固定的ip,虽然效果挺好的,但是还是想写在docker-compose里面. 这里提供两种方法固定 ...

  2. (五)Docker查看容器ip及指定固定IP

    如不懂Docker的网络模式及网络配置的请查看Docker四种网络模式和Docker网络配置 一.Docker如何查看容器ip docker inspect <container-ID> ...

  3. 固定docker容器IP方法

    docker 默认有4种网络模式,详细可查看我曾经写的 "docker几种网络模式" docker run 新建并启动容器时,不指定网络,默认是使用桥接模式,容器内部IP是通过DH ...

  4. docker容器的网络配置,允许docker可以被宿主机以外的其它主机访问以及局域网内可以直接访问docker容器ip

    自从Docker容器出现以来,容器的网络通信就一直是被关注的焦点,也是生产环境的迫切需求.容器的网络通信又可以分为两大方面:单主机容器上的相互通信,和跨主机的容器相互通信. 一.端口映射(局域网,外网 ...

  5. Nginx容器日志收集方案fluentd+elasticsearch+kilbana

    容器技术在发展到今天已经是相当的成熟,但容器不同于虚拟机,我们在使用容器的同时也有很多相关的技术问题需要解决,比如:容器性能监控,数据持久化,日志监控与分析等.我们不能像平时使用虚拟机一样来管理容器, ...

  6. Nginx容器动态流量管理方案-nginx-upsync-module+nginx_upstream_check_module初体验

    缘起 最近一直在研究日志收集系统的框架,之前在线游戏的数据发送都是由游戏服务器发送的,我来之前一直是rsync传输,也还算稳定.但现在上了单机游戏,只能由手机客户端直接发送,dau比较高,最近很火的& ...

  7. docker 创建容器时指定容器ip

    docker 创建容器时指定容器ip Docker创建容器时默认采用bridge网络,自行分配ip,不允许自己指定. 在实际部署中,我们需要指定容器ip,不允许其自行分配ip,尤其是搭建集群时,固定i ...

  8. docker容器IP的设置

    Docker创建容器时默认采用bridge网络,自行分配ip,不允许自己指定.在实际部署中,我们需要指定容器ip,不允许其自行分配ip,尤其是搭建集群时,固定ip是必须的.我们可以创建自己的bridg ...

  9. win10固定本机IP地址方案总结

    win10固定本机IP地址方案总结 1.需求背景 作为程序开发人员来说,在一些特定的时候需要固定本地的IP地址,比如暴露自己IP地址的时候不用每次都去查询. 2.解决方案 无论是无线网还是以太网,其操 ...

最新文章

  1. 连接ORACLE实例
  2. 中国牡蛎碳酸钙市场需求现状调研及十四五投资风险评估报告2022-2028年版
  3. linux shell 等待输入_linux运维——基础篇
  4. 「项目已被 macOS 使用,不能打开」的处理办法
  5. IOS学习笔记之 Socket 编程
  6. mysql下载备份数据库命令行_MYSQL 数据库导入导出命令 | 很文博客
  7. Java并发包的理解
  8. Maxscript开发笔记
  9. PHP内容管理系统详细制作步骤
  10. 【一句日历】2019年9月
  11. 101. 熟悉 Java 并发吗,谈谈对 JUC 线程池 ThreadPoolExecutor 的认识吧
  12. ttl低电平接大电阻_电压不稳定?那是你不懂上拉/下拉电阻原理,5分钟教你应用!...
  13. UE4 Spline的使用
  14. 中金财富后台开发一面经验分享
  15. ElasticSeach详细安装教程--图文介绍超详细
  16. 美团专家:35岁是程序员的终点?
  17. 最新版Visual Studio Code下载及远程连接服务器(很详细哦)
  18. 【常见问题】Waki_谢老师B站的HCNP/HCIP课程第27集的华为eNSP路由器配置问题——百兆口不能添加IP地址
  19. 【转载】关于 .Net 逆向的那些工具:反编译篇
  20. hdu4525威威猫系列故事——吃鸡腿

热门文章

  1. MXD修改数据源 arcgis
  2. 零基础玩转ROS小车
  3. Pix2Pix原理解析
  4. Web jsp开发学习——网上直播聊天室的简单开发
  5. 查oracle操作日志,查寻oracle的操作日志
  6. 蓝桥杯倒数七天冲刺国一之每日复习第五天
  7. 人脸识别之Hog特征+SVM分类器训练与使用
  8. 开源OA:手把手教你搭建OA办公系统(17)实现系统间单点登陆认证
  9. 9.01-常用网址归纳
  10. 成为一个好员工的七个忠告