kubernetes的网络入口

kubernetes通过创建workload包括deployment, job, ReplicaSet等来抽象pod。这解决了我们需要通过多个pod来定义一个应用的问题。然后kubernetes又通过service来抽象workload的入口。最后kubernetes在service的基础之上,kubernetes又抽象了ingress来管理服务的外部入口。

因此,要提到kubernetes中应用的外部接入口就必须提到ingress. 在ingress出现之前,kubernetes还定义了两种方法来暴露集群内部的应用到外界的端口,一种的nodeport,一种是load balancer.

NodePort

NodePort对于kubernetes中的应用而言,就像是docker容器配置时的端口映射。我们可以给一个service配置nodeport(30000 - 某个端口号),这样对于集群所在的某个node的ip,我们就可以通过ip:nodeport来访问该服务。但这种方法一般只用在调试期间。

Load Balancer

要让kubernetes的某个服务通过Load balancer来访问服务,我们必须向某个云供应商购买load balancer的使用授权。我们可以给每一个服务与云供应商的一个Load balancer建立关系,这样就可以通过对load balancer的访问来访问集群中的服务了。如果这么粗糙的使用load balancer会非常麻烦,因为每个服务都用了不一样的load balancer。这不但费钱,而且不方便。

Ingress

Ingress是kubernetes提供的终极解决方案,它允许我们通过配置ingress资源,借助一个ingress 控制器,将集群中的服务形成一个统一的对外的接口。值的一提的是,ingress可以通过nodeport对外开放,也可以通过load balancer对外开放。当ingress通过nodeport对外开放时,外部对集群中服务的访问就被统一到某个node的nodeport上。在生产环境下,ingress通过load balancer对外开放才是正道。

kubernetes配置默认的storageClass

默认的storageClass在动态创建pv时非常重要,在有一些场合我们需要改变kubenetes的默认storageClass。

我们可以用以下命令来配置一个storageClass是否为默认

以下指令将名称为standard的storageclass配置为不是默认类

kubectl patch storageclass standard -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"false"}}}'

以下指令将名称为gold的storageclass配置为默认类

kubectl patch storageclass gold -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'

我们可以通过以下指令查看storageclass

kubectl get storageclass

kubectl常用命令

kubectl get 查看一个或多个资源

kubectl get可以用来查看当前kubernetes集群的各种资源。

常用的有 kubectl get pods --all-namespaces

kubectl describle查看一个或一组资源

常用的比如:

kubectl describe pod <your_pod_name> -n <your_pod_namespace_if_necessary>

kubectl run 创建一个pod并运行一个指定的image

常用的比如:kubectl run -i -t --rm busybox --image=busybox --restart=Never

kubectl delete 移除某个资源

常用的比如: kubectl delete pod <your_pod_name> -n <your_pod_namespace_if_its_not_the_default_namespace>

在kubernetes中资源的定位很广泛,pv, pvc, storageClass, pod, node都是资源。范围用于资源的命令,其后面都可以是资源的任何一种。这里有非常详细的api参照

kubernetes创建nfs存储空间

在给kubenetes创建nfs存储空间之前,我们必须先有一个nfs服务器。我们可以参照此文来创建一个nfs服务器。创建好后,参照下文为kubenetes创建nfs供应系统

Deploying Service Account and Role Bindings

Next, we’ll configure a service account and role bindings. We’ll use role-based access control to do the configuration. First step is to download the nfs-provisioning repo and change into the nfs-provisioning directory.

  • git clone https://exxsyseng@bitbucket.org/exxsyseng/nfs-provisioning.git
  • cd nfs-provisioning

In this directory we have 4 files. (class.yaml default-sc.yaml deployment.yaml rbac.yaml) We will use the rbac.yaml file to create the service account for nfs and cluster role and bindings.

  • [vagrant@kmaster nfs-provisioning]$ kubectl create -f rbac.yaml

We can verify that the service account, clusterrole and binding was created.

  • [vagrant@kmaster nfs-provisioning]$ kubectl get clusterrole,clusterrolebinding,role,rolebinding | grep nfs

clusterrole.rbac.authorization.k8s.io/nfs-client-provisioner-runner 20m

clusterrolebinding.rbac.authorization.k8s.io/run-nfs-client-provisioner 20m
role.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner 20m
rolebinding.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner 20m

Deploying Storage Class

Next let’s run the “class.yaml” to set up the storageclass. A storageclass provides a way for administrators to describe the “classes” of storage they offer.

Let’s edit the “class.yaml” file and set both the storageclass name and the provisioner name.

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: managed-nfs-storage <--------------------注意,你可能需要修改此处
provisioner: example.com/nfs <--------------------注意,你可能需要修改此处
parameters:
archiveOnDelete: “false”

Once we’ve updated the class.yaml file we can execute the file using kubectl create

  • [vagrant@kmaster nfs-provisioning]$ kubectl create -f class.yaml
  • storageclass.storage.k8s.io/managed-nfs-storage created

Next, check that the storage class was created.

  • [vagrant@kmaster nfs-provisioning]$ kubectl get storageclass
  • NAME PROVISIONER AGE
  • managed-nfs-storage example.com/nfs 48s

Step 4) Deploying NFS Provisioner

Now let’s deploy the nfs provisioner. But first we’ll need to edit the deployment.yaml file. In this file we’ll need to specify the IP Address of our NFS Server (kmaster) 172.42.42.100.

  • kind: Deployment
  • apiVersion: apps/v1
  • metadata:
  • name: nfs-client-provisioner
  • spec:
  • selector:
  • matchLabels:
  • app: nfs-client-provisioner
  • replicas: 1
  • strategy:
  • type: Recreate
  • template:
  • metadata:
  • labels:
  • app: nfs-client-provisioner
  • spec:
  • serviceAccountName: nfs-client-provisioner
  • containers:
  • - name: nfs-client-provisioner
  • image: quay.io/external_storage/nfs-client-provisioner:latest
  • volumeMounts:
  • - name: nfs-client-root
  • mountPath: /persistentvolumes
  • env:
  • - name: PROVISIONER_NAME
  • value: example.com/nfs <--------------------注意,你可能需要修改此处,与上文的类别相同
  • - name: NFS_SERVER
  • value: 172.42.42.100 <--------------------注意,你可能需要修改此处
  • - name: NFS_PATH
  • value: /srv/nfs/kubedata <--------------------注意,你可能需要修改此处
  • volumes:
  • - name: nfs-client-root
  • nfs:
  • server: 172.42.42.100 <--------------------注意,你可能需要修改此处
  • path: /srv/nfs/kubedata <--------------------注意,你可能需要修改此处

Once we’ve made the changes, save the file and apply the changes by running “kubectl create”.

  • [vagrant@kmaster nfs-provisioning]$ kubectl create -f deployment.yaml
  • deployment.apps/nfs-client-provisioner created

After applying the changes, we should see a pod was created for nfs-client-provisioner.

  • [vagrant@kmaster nfs-provisioning]$ kubectl get all
  • NAME READY STATUS RESTARTS AGE
  • pod/nfs-client-provisioner-5b4f5775c7-9j2dw 1/1 Running 0 4m2s
  • NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
  • service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 2d22h
  • NAME READY UP-TO-DATE AVAILABLE AGE
  • deployment.apps/nfs-client-provisioner 1/1 1 1 4m2s
  • NAME DESIRED CURRENT READY AGE
  • replicaset.apps/nfs-client-provisioner-5b4f5775c7 1 1 1 4m2s

We can run “kubectl describe” to see more details about the pod.

  • [vagrant@kmaster ~]$ kubectl describe pod nfs-client-provisioner-5b4f5775c7-9j2dw
  • Name: nfs-client-provisioner-5b4f5775c7-9j2dw
  • Namespace: default
  • Priority: 0
  • Node: kworker2.example.com/172.42.42.102
  • Start Time: Sun, 03 Nov 2019 20:11:51 +0000
  • Labels: app=nfs-client-provisioner
  • pod-template-hash=5b4f5775c7
  • Annotations: cni.projectcalico.org/podIP: 192.168.136.65/32
  • Status: Running
  • IP: 192.168.136.65
  • IPs:
  • IP: 192.168.136.65
  • Controlled By: ReplicaSet/nfs-client-provisioner-5b4f5775c7
  • Containers:
  • nfs-client-provisioner:
  • Container ID: docker://95432ef4c256b48746b61f44a0292557b73abaced78342acafeae3c36681343b
  • Image: quay.io/external_storage/nfs-client-provisioner:latest
  • Image ID: docker-pullable://quay.io/external_storage/nfs-client-provisioner@sha256:022ea0b0d69834b652a4c53655d78642ae23f0324309097be874fb58d09d2919
  • Port: <none>
  • Host Port: <none>
  • State: Running
  • Started: Sun, 03 Nov 2019 20:11:56 +0000
  • Ready: True
  • Restart Count: 0
  • Environment:
  • PROVISIONER_NAME: example.com/nfs
  • NFS_SERVER: 172.42.42.100
  • NFS_PATH: /srv/nfs/kubedata
  • Mounts:
  • /persistentvolumes from nfs-client-root (rw)
  • /var/run/secrets/kubernetes.io/serviceaccount from nfs-client-provisioner-token-wgwct (ro)
  • Conditions:
  • Type Status
  • Initialized True
  • Ready True
  • ContainersReady True
  • PodScheduled True
  • Volumes:
  • nfs-client-root:
  • Type: NFS (an NFS mount that lasts the lifetime of a pod)
  • Server: 172.42.42.100
  • Path: /srv/nfs/kubedata
  • ReadOnly: false
  • nfs-client-provisioner-token-wgwct:
  • Type: Secret (a volume populated by a Secret)
  • SecretName: nfs-client-provisioner-token-wgwct
  • Optional: false
  • QoS Class: BestEffort
  • Node-Selectors: <none>
  • Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
  • node.kubernetes.io/unreachable:NoExecute for 300s
  • Events: <none>

给私有gitlab添加私有kubernetes集群

gitlab可以通过kubernetes集群安装和运行gitlab runner等应用,以实现其auto Devp的各种机制。能够给私有的gitlab配置好kubrenetes可以给项目开发省下很多功夫。

我们可以给gitlab中的一个工作群组创建Kubernetes,创建过程gitlab给出了很好的引导。这其中我们唯一需要注意的是,创建kubernetes的api url时有时候需要指定到具体的端口。例如 : https://ip_address:6443

但是,base domain不需要指定端口。只需要ip_address即可。

在创建过程中,你需要按照gitlab的说明在集群配置相应的服务账号,生成证书,生成token。如果你的kubernetes网络配置都正确的话,我们就可以通过gitlab给你刚刚所指定的kubenetes集群安装应用了。

在安装这些应用时,我们的第一个挑战出现了。安装gitlab-runner基本没有什么问题,安装Prometheus时因为它要指定一个存储空间,问题可能就会发生了。按照最基本的搭建kubernetes集群方法,并没有告诉我们什么时候给安装kubernetes存储空间,所以这里就会发生问题。

对于计算机集群而言,存储空间是个很严重的问题。因为pod一般是临时的,可能随时被创建,随时被移除。而pod所使用的一些数据有时候却需要持久化。从计算机集群的视角来看,存储空间就不是文件系统,或者数据库那么简单了。

像prometheus这种应用,它会向kubenetes申请一个存储空间,在申请时它会创建一个pvc来描述自己的需求,如果kubernetes发现自己能够按照它的需求创建,则会创建一个给prometheus使用。

在这里的情况下,我们需要kubenetes采用动态创建pv的方式给prometheus创建一个存储空间。要达到这个前提,我们就需要指定一个默认的storageClass。我们可以通过以下指令来查看kubunetes都有哪些存储类型。

kubectl get storageClass

如果此kubenetes是根据官方文档创建的空白集群,这里的输出有可能是空。我们需要给kubernetes创建一个storageClass并且指定其为默认的storageClass, 这样在gitlab安装prometheus时就能成功创建了。考虑到本地的存储的类型不能作为默认的storageClass,这里我们可以创建一个nfs服务器,并给kubenetes创建一个nfs的供应系统

在创建了nfs供应系统后,还需要参照此文的方法,给kubenetes配置正确的默认storageClass

单机安装kubernetes

因为测试和学习的目的,我必须在自己电脑上安装一个可用的kubernetes集群。以下记录安装过程

1 配置运行时容器的cgroup

首先,我自己这边采用的docker作为kubertetes的运行时容器,由于kubernetes默认采用cgroupfs作为其默认cgroup,我们必须改变这个默认值(根据官方介绍,如果docker和主机采用不同的cgroup可能会导致在系统资源紧张时发生不可预见的错误)。

配置方法: 给docker的守护进程配置如下文件指定docker采用systemd的cgroup:

# Set up the Docker daemon
cat <<EOF | sudo tee /etc/docker/daemon.json
{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m"
  },
  "storage-driver": "overlay2",
  "storage-opts": [
    "overlay2.override_kernel_check=true"
  ]
}
EOF

配置完成后,重启docker

# Restart Docker
sudo systemctl daemon-reload
sudo systemctl restart docker

2 关闭系统swap

# 临时
swapoff -a

修改 /etc/fstab 文件,注释掉 SWAP 的自动挂载(永久关闭swap,重启后生效)

# 永久
/dev/mapper/cl-swap     swap                    swap    defaults        0 0

3 关闭selinux

据官方介绍,selinux会与kubernetes的一些功能相冲突,在selinux项目作出调整之前,我们必须关闭调selinux.

# Set SELinux in permissive mode (effectively disabling it)
sudo setenforce 0
sudo sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config

4 检查所需要的端口是否开放

kubernetes的api-server运行时需要开放各种端口。如果嫌麻烦,可以直接粗暴一点:关闭防火墙。 sudo systemctl stop firewalld

需要注意的一点时,在我的实际使用过程中,发现防火墙还会组织pod内容器对外界域名服务器的访问。在没找到更好的配置防火墙方案之前,我们这里必须要关闭调防火墙。

5 配置iptable

cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sudo sysctl --system

6 安装kubeadm, kubelet, kubectl

sudo yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes

sudo systemctl enable --now kubelet

7 初始化kubelet

kubelet是kubernetes的守护进程,对它很好的初始化,几乎等价于针对某个node安装好kubernetes。

考虑到后面我们准备采用calico来作为kubernetes的网络插件使用,我们初始化时需要根据calico的安装指导来指定--pod-network-cidr=192.168.0.0/16

sudo kubeadm init --pod-network-cidr=192.168.0.0/16 --api-server-advertise=<your_ip_address>

8 建立好本地kubectl配置文件

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

如果不这么做,kubectl运行时会报认证错误

9 安装网络插件

kubernetes是计算机集群,对于集群而言,它需要一个网络系统能够让集群中的计算机互相通信,管理集群内部和集群外部的交通。kubernetes可以支持的网络插件很多,我们这里采用calico插件。

kubectl create -f https://docs.projectcalico.org/manifests/tigera-operator.yaml
kubectl create -f https://docs.projectcalico.org/manifests/custom-resources.yaml

需要注意的是,安装应该保持网络配置不变(不要切换vpn, 否则可能会导致不可预见的错误)。如果在安装一些文件时必须使用vpn,我们可以考虑先通过vpn把文件下载下来,然后再通过kubectl create -f 指定本地的相应文件。

可以通过以下命令来查看calico系统是否安装成功(处于running状态)

watch kubectl get pods -n calico-system

10 运行master结点下创建worker类型的pod

到这一步之前,如果没有发生什么错误的话,我们已经成功安装好了kubernetes。但考虑到我这里的特殊性,我只有一台电脑,也就是一个node。在kubernetes默认的机制里是不允许工作pod和控制pod位于一个node中的。我必须把kubernetes的这个默认机制改变:

kubectl taint nodes --all node-role.kubernetes.io/master-

到此,一切顺利的话,单主机的kubernetes集群就安装完毕了。我们可以通过kubectl apply等命令来创建pod了。