极客时间 《Kubernetes 入门实战课》 by 罗剑锋
github上的配套学习项目

全笔记:
《开篇词 (2讲)》
《入门篇 (8讲)》
《初级篇 (9讲)》
《中级篇 (8讲)》
《高级篇 (10讲)》
《加餐分享 (2讲)》

《17|更真实的云原生:实际搭建多节点的Kubernetes集群》

  • 什么是 kubeadm
    kubeadm,原理和 minikube 类似,也是用容器和镜像来封装 Kubernetes 的各种组件,但它的目标不是单机部署,而是要能够轻松地在集群环境里部署 Kubernetes,并且让这个集群接近甚至达到生产级质量。

  • 安装前的准备工作

第一,由于 Kubernetes 使用主机名来区分集群里的节点,所以每个节点的 hostname 必须不能重名。改名:sudo vi /etc/hostname

第二,安装Docker作为容器运行时。我:注意这里也要选择docker版本,不然后面会和编者的旧版本k8s不兼容。

sudo apt install -y docker.io=20.10.12-0ubuntu4

在这里插入图片描述

#锁定版本,防止升级:
sudo apt-mark hold docker.io containerd

sudo usermod -aG docker ${USER}   #当前用户加入docker组

配置docker镜像源, 以及把cgroup 的驱动程序改成 systemd等:sudo vim /etc/docker/daemon.json :

{ 
   "registry-mirrors": [
    "https://docker.m.daocloud.io",
    "https://docker.mirrors.ustc.edu.cn",         
    "https://hub-mirror.c.163.com"
  ],
   "exec-opts": ["native.cgroupdriver=systemd"],  
   "log-driver": "json-file", 
    "log-opts": {    "max-size": "100m"  },  
    "storage-driver": "overlay2"
}
sudo systemctl enable docker #启用Docker服务,使其在系统启动时自动运行
sudo systemctl daemon-reload
sudo systemctl restart docker

运行docker version 和 docker info来验证 Docker 是否安装成功了。

第三,为了让 Kubernetes 能够检查、转发网络流量,修改 iptables 的配置,启用br_netfilter模块:

cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
br_netfilter
EOF
sudo modprobe br_netfilter

cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward=1 # better than modify /etc/sysctl.conf
EOF

sudo sysctl --system

第四,需要修改“/etc/fstab”,关闭 Linux 的 swap 分区 :

sudo swapoff -a
sudo sed -ri '/\sswap\s/s/^#?/#/' /etc/fstab
  • 安装 kubeadm, 这里指定了版本
sudo apt install -y apt-transport-https ca-certificates curl

curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | sudo apt-key add -

cat <<EOF | sudo tee /etc/apt/sources.list.d/kubernetes.list
deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main
EOF

sudo apt update


sudo apt install -y kubeadm=1.23.3-00 kubelet=1.23.3-00 kubectl=1.23.3-00

验证:
kubeadm version
kubectl version --short

可锁定三个软件的版本,避免意外升级导致版本错误:sudo apt-mark hold kubeadm kubelet kubectl

  • 安装 Master 节点,不需要像文中说的手动下载 Kubernetes 组件镜像
sudo kubeadm init \
--apiserver-advertise-address=192.168.56.103 \
--image-repository=registry.aliyuncs.com/google_containers \
--kubernetes-version=v1.23.3 \
--pod-network-cidr=10.10.0.0/16

如果init失败,可以使用 sudo kubeadm reset -f 进行重置

过程中一度因为版本冲突等原因失败,可查看详细日志定位精准原因:
journalctl -u kubelet -f #实时看kubelet日志
journalctl -u kubelet --no-pager -n 50 #导出最近50行错误日志
在这里插入图片描述
豆包说:在这里插入图片描述

终于init成功:
在这里插入图片描述

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

验证成功:在这里插入图片描述

  • 安装 Flannel 网络插件
    下载https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml, 把其中的10.244.0.0/16替换为前面设置的podCIDR(这里是10.10.0.0/16),然后安装并验证:
    在这里插入图片描述
    注意这里要设置网卡(据说是因为我们虚拟机双网卡的缘故),否则在后续的第20小节,尝试以DNS方式使用 Service时会失败:
    在这里插入图片描述

  • 安装 Worker 节点
    Worker 节点,前面的步骤和Master节点一样,不需要最后两步(kubeadm init,和安装 Flannel 网络插件)。

使用前面在master节点kubeadm init成功截图中的kubeadm join命令。
在这里插入图片描述
注:master的token过24小时会失效,这时需要在Master重新生成新token:kubeadm token create --print-join-command,再执行kubeadm join命令。

过阵子就可以在master节点上看到Ready的worker节点了:
在这里插入图片描述

在worker节点上想成功调用kubectl,还得把master节点上的config文件拷过来:

mkdir -p $HOME/.kube
scp sdh@192.168.56.103:~/.kube/config $HOME/.kube/config
  • 小结
    Console节点的部署工作更加简单,它只需要安装一个 kubectl,不需要docker等。

下载和安装kubectl:

curl -LO https://dl.k8s.io/release/v1.23.3/bin/linux/amd64/kubectl
sudo install kubectl /usr/local/bin/kubectl

和workder节点一样,复制master节点上的config文件。

附:本小节的整个搭建过程有部分参考了1

《18|Deployment:让应用永不宕机》

  • 如何使用 YAML 描述 Deployment
    在这里插入图片描述

把它和 Job对比一下,你会发现有相似也有不同。相似的地方是都有“spec”“template”字段,“template”字段里也是一个 Pod;不同的地方在于它的“spec”部分多了 replicas、selector 这两个新字段,这两个新字段就是 Deployment 实现多实例、高可用等功能的关键所在。

  • Deployment 的关键字段
    在线业务和离线业务(Job/CronJob)的应用场景差异很大。离线业务中的 Pod 基本上是一次性的,只与这个业务有关,紧紧地绑定在 Job 对象里,一般不会被其他对象所使用。
    而在线业务就要复杂得多了,因为 Pod 永远在线,除了要在 Deployment 里部署运行,还可能会被其他的 API 对象引用来管理,比如负责负载均衡的 Service 对象。所以 Deployment 和 Pod 实际上是一种松散的组合关系,Deployment 实际上并不“持有”Pod 对象,它只是帮助 Pod 对象能够有足够的副本数量运行,仅此而已。
    通过标签这种设计,Kubernetes 解除了 Deployment 和模板里 Pod 的强绑定,把组合关系变成了“弱引用”。

  • 如何使用 kubectl 操作 Deployment
    在 Deployment 部署成功之后,你还可以随时调整 Pod 的数量,实现所谓的“应用伸缩”
    kubectl scale

在使用 kubectl get 命令的时候,加上参数 -l,使用 ==、!=、in、notin 的表达式,就能够很容易地用“标签”筛选、过滤出所要查找的对象:
在这里插入图片描述

《19|Daemonset:忠实可靠的看门狗》

  • 为什么要有 DaemonSet
    DaemonSet 的目标是在集群的每个节点上运行且仅运行一个 Pod,就好像是为节点配上一只“看门狗”
  • 如何使用 YAML 描述 DaemonSet
    Kubernetes 的官网上有DaemonSet 的 YAML 示例

在这里插入图片描述
DaemonSet 在 spec 里没有 replicas 字段,这是它与 Deployment 的一个关键不同点,意味着它不会在集群里创建多个 Pod 副本,而是要在每个节点上只创建出一个 Pod 实例。

  • 什么是污点(taint)和容忍度(toleration)
    我:污点(taint)是node的属性,容忍度(tolerations)是Pod的属性。如果一个node指定了效果为NoSchedule的污点,只有设置了对应容忍度的pod才可能调度到此node。
    污点的不同效果(参考豆包):
效果 能否调度新 Pod 存量运行 Pod
NoSchedule 完全禁止 保留,不驱逐
PreferNoSchedule 尽量不调度,资源不够仍可调度 保留,不驱逐
NoExecute 完全禁止 直接驱逐
    • 查看、编辑node的污点:

kubectl describe node master命令可以看到master 节点默认有一个 taint,名字是 node-role.kubernetes.io/master,它的效果是 NoSchedule,也就是说这个污点会拒绝 Pod 调度到本节点上运行,而 worker 节点的 taint 字段则是空的:
在这里插入图片描述

k8s官网:污点和容忍度
在这里插入图片描述

e.g., 去掉节点master上的指定taint(key为node-role.kubernetes.io/master,value为空,效果为NoSchedule):kubectl taint node master node-role.kubernetes.io/master:NoSchedule-; 这条命令去掉最后的-号,就是反过来给node加污点。

    • 为 Pod 添加字段 tolerations,让它能够“容忍”某些“污点” :
      在这里插入图片描述
      “容忍度”并不是 DaemonSet 独有的概念,而是从属于 Pod,所以理解了“污点”和“容忍度”之后,你可以在 Job/CronJob、Deployment 里为它们管理的 Pod 也加上 tolerations,从而能够更灵活地调度应用。
  • 什么是静态 Pod
    静态 Pod 不受 Kubernetes 系统的管控,不与 apiserver、scheduler 发生关系,由kubelet直接读取本地配置文件创建(默认在在节点的 /etc/kubernetes/manifests 目录)

《20|Service:微服务架构的应对之道》

  • 为什么要有 Service
    Service 的工作原理和 LVS、Nginx 差不多,Kubernetes 会给它分配一个静态 IP 地址,然后它再去自动管理、维护后面动态变化的 Pod 集合,当客户端访问 Service,它就根据某种策略,把流量转发给后面的某个 Pod。
    豆包:Kube-proxy 支持三种代理模式:userspace、iptables、ipvs,集群同一时间仅启用其中一种。每个节点的 kube-proxy 会根据当前选定的模式,自动维护对应底层转发规则,实现 Service 到后端 Pod 的流量转发与负载均衡。

  • 如何使用 YAML 描述 Service
    service使用命令kubectl expose而非kubectl create进行创建,需要用参数 --port 和 --target-port 分别指定映射端口和容器端口(豆包: ServiceIP:port → 转发到 PodIP:targetPort)。e.g. , 为deployment ngx-dep对象生成 Service YAML:

export out="--dry-run=client -o yaml"
kubectl expose deploy ngx-dep --port=80 --target-port=80 $out

可以看到Kubernetes为我们自动填上了deployment ngx-dep的标签
在这里插入图片描述
我的观察:pod.spec.containers.ports.containerPort 不会影响程序在容器内部的行为(即它监听的端口)。
豆包说它的真正作用有:1)创建 Service 时,如果只写 port 不写 targetPort,K8s 会自动按ServiceIP:port → PodIP:containerPort 转发;2)健康探针默认端口等。

  • 如何在 Kubernetes 里使用 Service
    此例中Service 对象管理了两个 endpoint。把 Pod 的地址与 Service 的信息做个对比,我们就能够验证 Service 确实用一个静态 IP 地址代理了两个 Pod 的动态 IP 地址:
    在这里插入图片描述

  • 如何以域名的方式使用 Service
    使用命令 kubectl get ns 来查看当前集群里都有哪些名字空间(namespace)
    Service 对象的域名完全形式是“对象. 名字空间.svc.cluster.local”

我:一般来说,k8s集群内的所有Pod和所有Node, 都能访问Service的ClusterIP。比如我在worker节点上,执行curl clusterIP能成功,是因为所在节点的kube-proxy按 iptables/ipvs 规则拦截了TCP 流量,转发到Pod。而与k8s节点在同一网段的其它机器(换句话说,互相能ping通,但它不在k8s集群),curl clusterIP自然就不能成功了。
我又观察到在worker node上能curl clusterIP成功,却不能成功curl service的域名。而在进入一个pod后,两者都能成功。豆包的解释:service的域名解析依赖CoreDNS,CoreDNS为集群内Pod做DNS解析配置,但不会自动为Node配置。

  • 如何让 Service 对外暴露服务

Service 对象有一个关键字段type,表示 Service 是哪种类型的负载均衡。除了默认值ClusterIP,Service 还支持其他三种类型,分别是ExternalName, LoadBalancer, NodePort。ClusterIP只能在集群内部访问。

NodePort 类型的 Service,会在每个节点上都开端口,然后使用 kube-proxy 路由到真正的后端 Service;
而且它要求向外界暴露节点的 IP 地址,这在很多时候是不可行的。
在这里插入图片描述
在这里插入图片描述

《21|Ingress:集群进出流量的总管》

  • 为什么要有 Ingress
    Service本质上是一个由 kube-proxy 控制的四层负载均衡,在 TCP/IP 协议栈上转发流量。但在四层上的负载均衡功能还是太有限了。而且Service比较适合代理集群内部的服务。如果想要把服务暴露到集群外部,就只能使用 NodePort 或者 LoadBalancer 这两种方式,而它们都缺乏足够的灵活性,难以管控。
    在这里插入图片描述

  • 为什么要有 Ingress Controller
    Service 本身是没有服务能力的,它只是一些 iptables 规则,真正配置、应用这些规则的实际上是节点里的 kube-proxy 组件。如果没有 kube-proxy,Service 定义得再完善也没有用。
    同样的,Ingress 也只是一些 HTTP 路由规则的集合(YAML 配置),真正要把这些规则在集群里实施运行,靠的是 Ingress Controller。它的作用就相当于 Service 的 kube-proxy。

  • 为什么要有 IngressClass
    不同的Ingress Class可用来定义不同业务网关,让Ingress 和 Ingress Controller解耦

  • 如何使用 YAML 描述 Ingress/Ingress Class

Ingress 也是可以使用 kubectl create 来创建样板文件的,它需要用两个附加参数:
--class,指定 Ingress 从属的 Ingress Class 对象。
--rule,指定路由规则,基本形式是“URI=Service”,也就是说是访问 HTTP 路径就转发到对应的 Service 对象。
e.g. :

export out="--dry-run=client -o yaml"
kubectl create ing ngx-ing --rule="ngx.test/=ngx-svc:80" --class=ngx-ink $out

生成的Ingress 的 YAML 里,有两个关键字段:ingressClassName和rules,分别对应了上述命令行参数。

Ingress Class的YAML在spec里只有一个必需的字段controller,表示要使用哪个 Ingress Controller,比如Nginx 开发的 Ingress Controller,那么就要用名字“nginx.org/ingress-controller”
在这里插入图片描述
ingress yaml中的spec.rules[].host 用来匹配HTTP header中的Host字段。

  • 如何在 Kubernetes 里使用 Ingress Controller
    安装Nginx Ingress Controller。评论里提到只运行正文中的那4个YAML是不行的,得运行教程项目ingress目录下的setup.sh。
    下载kic.yml文件并略微修改,运行, Ingress Controller 就算是运行起来了。
    在这里插入图片描述最后,因为 Ingress Controller 本身也是一个 Pod,想要向外提供服务还要再为它定义一个 Service,使用 NodePort 或者 LoadBalancer 暴露端口。

curl --resolve 指定域名的解析规则,不会影响发送的HTTP header中的Host字段。

我发现kubectl port-forward 这条命令,即使在console机器(指非k8s节点,只是安装了kubectl的机器)上,都可以成功运行。

  • 小结
    在这里插入图片描述
    评论中有提到:Ingress只支持http/1.1,所以不支持grpc。其他的协议需要用Ingress Controller的CRD。
    据豆包说:Ingress不再维护,新的:Gateway

《22|实战演练:玩转Kubernetes(2)》

  • WordPress 网站基本架构
    网站对外提供服务我选择了两种方式。一种是让 WordPress 的 Service 对象以 NodePort 的方式直接对外暴露端口 30088,方便测试;另一种是给 Nginx Ingress Controller 添加hostNetwork属性,直接使用节点上的端口号,类似 Docker 的 host 网络模式,好处是可以避开 NodePort 的端口范围限制。

    1. WordPress 网站部署 WordPress

为 WordPress 创建 Service 对象,这里使用了NodePort类型,并且手工指定了端口号30088(必须在 30000~32767 之间):

apiVersion: v1
kind: Service
metadata:
  labels:
    app: wp-dep
  name: wp-svc

spec:
  ports:
  - name: http80
    port: 80
    protocol: TCP
    targetPort: 80
    nodePort: 30088

  selector:
    app: wp-dep
  type: NodePort

部署成功后,就可以在浏览器里通过http://nodeIP:30088看到 WordPress 的安装界面了。

    1. WordPress 网站部署 Nginx Ingress Controller

这个 Ingress Controller 不使用 Service,而是给它的 Pod 加上一个特殊字段 hostNetwork,让 Pod 能够使用宿主机的网络。
我的补充:这Pod containers下的securityContext.allowPrivilegeEscalation字段要设为true,否则这个pod不能ready。豆包的解释:配置用的普通用户nginx,不是root, 配置了hostNetwork,又需要监听宿主机的80、443、8081等端口。普通用户直接开80端口会被内核拒绝,需要提权。

为了在集群外的主机上必须能够识别我们的wp.test域名,也就是说要把域名wp.test解析到 Ingress Controller 所在的节点上。因为我用的是 Windows,就修改 C:\Windows\System32\Drivers\etc\hosts,添加一条解析规则:192.168.56.104 wp.test
我的补充:千万记得关闭VPN的DNS覆写
在这里插入图片描述
评论区有个好问题:wp.test这个域名需要指定ingress controller那个pod所在的节点ip,而ingress controller是通过deployment来管理的,pod重建时可能会被部署到别的节点,这样不是又要改hosts配置了吗?生产环境是怎样解决这个问题的?作者回复: 生产环境一般为Ingress Controller配置type LoadBalancer的service,云厂商会自动分配IP地址。

《23|视频:中级篇实操总结》

  • 七. Ingress 的使用
    • 视频1:43
      Ingress负载均衡算法字段metadata.annotations.nginx.org/lb-method(豆包说是旧版)

《加餐|docker-compose:单机环境下的容器编排工具》

  • 什么是 docker-compose
  • 如何使用 docker-compose

我注:和第17小节一样,有版本冲突,需要安装docker时指定版本,比如20.10.12-0ubuntu4

下载docker-compose:

sudo curl -SL https://github.com/docker/compose/releases/download/v2.6.1/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose

sudo chmod +x /usr/local/bin/docker-compose
sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose

docker-compose version  #验证

docker-compose 里管理容器的核心概念是service。注意,它与 Kubernetes 里的 Service 虽然名字很像,但却是完全不同的东西

services:
  registry:
    image: registry
    container_name: registry
    restart: always
    ports:
      - 5000:5000

启动应用:docker-compose -f reg-compose.yml up -d
在这里插入图片描述
停止应用,使用 docker-compose down 命令:docker-compose -f reg-compose.yml down

  • 使用 docker-compose 搭建 WordPress 网站
services:

  mariadb:
    image: mariadb:10
    container_name: mariadb
    restart: always

    environment:
      MARIADB_DATABASE: db
      MARIADB_USER: wp
      MARIADB_PASSWORD: 123
      MARIADB_ROOT_PASSWORD: 123


  wordpress:
    image: wordpress:5
    container_name: wordpress
    restart: always

    environment:
      WORDPRESS_DB_HOST: mariadb
      WORDPRESS_DB_USER: wp
      WORDPRESS_DB_PASSWORD: 123
      WORDPRESS_DB_NAME: db

    depends_on:
      - mariadb


  nginx:
    image: nginx:alpine
    container_name: nginx
    hostname: nginx
    restart: always
    ports:
      - 80:80
    volumes:
      - ./wp.conf:/etc/nginx/conf.d/default.conf

    depends_on:
      - wordpress

字段 depends_on,它用来设置容器的依赖关系,指定容器启动的先后顺序


  1. https://blog.csdn.net/xuezhiwu001/article/details/128444657?spm=1001.2014.3001.5501 ↩︎

更多推荐