安装#

配置 repo:#

[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg

安装:#

yum install -y kubelet kubeadm kubectl kubernetes-cni cri-tools
systemctl enable kubelet --now
kubeadm init --image-repository=registry.cn-hangzhou.aliyuncs.com/google_containers --kubernetes-version v1.18.0

使用 macvlan:#

{
  "plugins": [
    {
      "cniVersion": "0.4.0",
      "name": "macvlannet",
      "type": "macvlan",
      "master": "eth0",
      "mode": "vepa",
      "isGateway": true,
      "ipMasq": false,
      "ipam": {
        "type": "dhcp"
      }
    }
  ]
}

启动 DHCP 客户端:#

/opt/cni/bin/dhcp daemon
  • vepa 模式下需要交换机配置 hairpin mode ,否则 host-containercontainer-container 都不通。

  • bridge 模式下不配置 hairpin host-container 不通, container-container 通。

  • bridge 模式下 host 配置 macvlan 子接口, host-container 通, container-container 通。

ip link add mac0 link eno1.100 type macvlan mode bridge
ip addr add 192.168.2.11/24 dev mac0
ip link set mac0 up
ip route add default via 192.168.2.1

网络#

calico#

本地集群安装#

  • 使用 calico bgp 网络
curl https://docs.projectcalico.org/manifests/calico.yaml -O

主要添加一个检测网卡的项和配置 pod ip 的 cidr:

containers:
# Runs calico-node container on each Kubernetes node. This
# container programs network policy and routes on each
# host.
- name: calico-node
  image: calico/node:v3.16.3
  envFrom:
  - configMapRef:
# Allow KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT to be overridden for eBPF mode.
    name: kubernetes-services-endpoint
    optional: true
  env:
  - name: IP_AUTODETECTION_METHOD
    value: "interface=.*100$|.*100@.*"
    # other config
  - name: CALICO_IPV4POOL_CIDR
    value: "192.168.100.0/24"

apply 之后生成 calico-node 的 daemonSet 和一个 calico-kube-controllersdeployment.

$ kubectl apply -f calico.yaml

官网文档

如果使用 etcd ,则可以 apply 官网提供的 calico-etcd.yaml

calicoctl#

可以直接在运行 calico-node 的节点上下载 calicoctl

curl -O -L https://github.com/projectcalico/calicoctl/releases/download/v3.16.3/calicoctl

calicoctl node status 可以直接在 node 上运行,但其他一些操作需要连接到 datastore. 连接方式在这篇文档中。也可以使用环境变量:

DATASTORE_TYPE=kubernetes KUBECONFIG=~/.kube/config calicoctl get nodes

calicoctl 也可以运行在 k8s 中,并使用 etcdkubernetes api, 不需要配置连接 datastore.

kubectl apply -f https://docs.projectcalico.org/manifests/calicoctl.yaml

不过这样需要在 pod 中执行 calicoctl

kubectl exec -ti -n kube-system calicoctl -- /calicoctl get profiles -o wide

可以配置 cidrblocksize, 这样这个 node 上将使用相应大小的 cidr块,宣告的路由也是汇聚路由:

kubectl exec -ti -n kube-system calicoctl -- /calicoctl patch ippool default-ipv4-ippool -p '{"spec":{"blockSize":26}}'

使用 bgp,需要 bgpconfigrationbgppeer

---
apiVersion: projectcalico.org/v3
kind: BGPConfiguration
metadata:
  name: default
spec:
  logSeverityScreen: Info
  nodeToNodeMeshEnabled: false
  asNumber: 100
  serviceClusterIPs:
  - cidr: 10.96.0.0/12
  serviceExternalIPs:
  - cidr: 1.1.0.0/16
  listenPort: 179
---

---
apiVersion: projectcalico.org/v3
kind: BGPPeer
metadata:
  name: node-10-peer
spec:
  peerIP: 172.1.254.5
  asNumber: 100
  nodeSelector: kubernetes.io/hostname == "k8s-node-1"
---

使用 calicoctl apply 这些文件。

kubectl exec -ti -n kube-system calicoctl -- /calicoctl apply -f - < file.yaml

存储#

使用持久存储时,需要 storageclass, 可以是远程存储,例如 ceph 等,也可以使用本地存储:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer

pod 使用 pvc 申请使用 pv, 匹配的 pv 会分配给 pvc.

使用本地存储时,没有 provisioner, 因此需要手动创建 pv 或使用 github 上的一些 provisioner.

apiVersion: v1
kind: PersistentVolume
metadata:
  name: example-local-pv-1
spec:
  capacity:
    storage: 1Gi
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: local-storage
  local:
    path: /mnt/disks/vol1
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - k8s-master

本地存储需要指定 node,且使用本地存储的 pod 无法迁移到其他 node 上。 spec.local.path 需要事先创建。

设置默认 storageclass

问题#

macvlan vepa 模式 coredns 无法就绪#

…… Warning Unhealthy 19s (x17 over 2m59s) kubelet, 11 Readiness probe failed: HTTP probe failed with statuscode: 503

E0818 03:17:23.844791 1 reflector.go:153] pkg/mod/k8s.io/client-go@v0.17.2/tools/cache/reflector.go:105: Failed to list *v1.Service: Get https://10.96.0.1:443/api/v1/services?limit=500&resourceVersion=0: dial tcp 10.96.0.1:443: i/o timeout

一个原因是这种模式访问不到 service 的 clusterip,可尝试修改 svc 的 clusterIP None,使用 headless 的 service,直接访问 pod.

在 coreDNS 的 deployment 中修改 container 的 spec 使用 hostNetwork: True 也可以。

CentOS 7 和 CentOS 8 混合环境下不能正常设置 iptables#

CentOS 8 已经不提供 iptables-legacy 包,现在是使用 nft 管理,calico 中的 felix 需要使用 iptables 设置规则,目前来看需要显式在 calico-node 的 containers 中指定使用 FELIX_IPTABLESBACKEND = NFT:

kind: DaemonSet
apiVersion: apps/v1
metadata:
  name: calico-node-centos8
  namespace: kube-system
  labels:
    k8s-app: calico-node-centos8
spec:
  selector:
    matchLabels:
      k8s-app: calico-node-centos8
  updateStrategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1
  template:
    metadata:
      labels:
        k8s-app: calico-node-centos8
    spec:
      nodeSelector:
        kubernetes.io/os: linux
        os: centos8
      ...
      containers:
        # Runs calico-node container on each Kubernetes node. This
        # container programs network policy and routes on each
        # host.
        - name: calico-node
          image: calico/node:v3.16.3
		  ...
          env:
            ...
            - name: FELIX_IPTABLESBACKEND
              value: "NFT"

因为是混合环境,配置了多个 daemonset 为 centos8 和 centos7 分别指定。

附录#

Docker registry#

# vi /etc/docker/daemon.json
{
"registry-mirrors": ["http://hub-mirror.c.163.com"]"bridge": "none",									// 不要 docker 桥
"exec-opts": ["native.cgroupdriver=systemd"],		// k8s 推荐使用 systemd driver
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
},
"storage-driver": "overlay2"
}
# systemctl restart docker.service

杂项#

获取 base64 编码的 secret 的明文#

$ PASSWORD=$(kubectl get secret <scret name> -o go-template='{{.data.elastic | base64decode}}')

连接不通?#

可能是 flannel 没弄好路由,重新启动 flannel 试试!