Kubernetes学习之路(一)之概念和架构解析与环境准备

_____egon新书来袭请看:https://egonlin.com/book.html
  • 1、Kubernetes的重要概念

  • 1.1 节点
节点通常指的就是服务器。可以使物理机或虚拟机,在k8s中有两种节点:管理节点(Master Node)和工作节点(Worker Node)
管理节点(Master Node):负责管理整个k8s集群、是 Cluster 的大脑,主要职责是调度,即决定将应用放在哪里运行,一般由3个管理节点组成HA的架构。
工作节点(Worker Node):主要负责运行容器,Node 由 Master 管理,Node 负责监控并汇报容器的状态,并根据 Master 的要求管理容器的生命周期
  • 1.2 Pod 
Pod 是 Kubernetes 的最小工作单元。每个 Pod 包含一个或多个容器。
每个Pod内共享存储资源、网络资源 以及管理控制容器运行方式的策略选项。
Pod 中的容器会作为一个整体被 Master Node调度到一个 Worker Node 上运行。

1.2.1 Kubernetes 引入 Pod 主要基于下面两个目的:

    1. 可管理性。
      有些容器天生就是需要紧密联系,一起工作。Pod 提供了比容器更高层次的抽象,将它们封装到一个部署单元中。Kubernetes 以 Pod 为最小单位进行调度、扩展、共享资源、管理生命周期。

    2. 通信和资源共享。
      Pod 中的所有容器使用同一个网络 namespace,即相同的 IP 地址和 Port 空间。它们可以直接用 localhost 通信。同样的,这些容器可以共享存储,当 Kubernetes 挂载 volume 到 Pod,本质上是将 volume 挂载到 Pod 中的每一个容器。

1.2.2 Pods 有两种使用方式:

    1. 运行单一容器。
      one-container-per-Pod 是 Kubernetes 最常见的模型,这种情况下,只是将单个容器简单封装成 Pod。即便是只有一个容器,Kubernetes 管理的也是 Pod 而不是直接管理容器。

    2. 运行多个容器。
      但问题在于:哪些容器应该放到一个 Pod 中? 
      答案是:这些容器联系必须 非常紧密,而且需要 直接共享资源。

   举个例子。

   下面这个 Pod 包含两个容器:一个 File Puller,一个是 Web Server。

 

   File Puller 会定期从外部的 Content Manager 中拉取最新的文件,将其存放在共享的 volume 中。Web Server 从 volume 读取文件,响应 Consumer 的请求。

   这两个容器是紧密协作的,它们一起为 Consumer 提供最新的数据;同时它们也通过 volume 共享数据。所以放到一个 Pod 是合适的。

   再来看一个反例:是否需要将 Tomcat 和 MySQL 放到一个 Pod 中?

   Tomcat 从 MySQL 读取数据,它们之间需要协作,但还不至于需要放到一个 Pod 中一起部署,一起启动,一起停止。同时它们是之间通过JDBC 交换数据,并不是直接共享存储,所以放到各自的 Pod 中更合适。 

  • 1.3 Controller (共有5大pod控制器)

Kubernetes 通常不会直接创建 Pod,而是通过 Controller 来管理 Pod 的。Controller 中定义了 Pod 的部署特性,比如有几个副本,在什么样的 Node 上运行等。为了满足不同的业务场景,Kubernetes 提供了多种 Controller,包括 Deployment、ReplicaSet、DaemonSet、StatefuleSet、Job 等,我们逐一讨论。

1.3.1、Deployment 是最常用的 Controller,比如前面在线教程中就是通过创建 Deployment 来部署应用的。Deployment 可以管理 Pod 的多个副本,并确保 Pod 按照期望的状态运行。

1.3.2、replicaSet(副本集) 实现了 Pod 的多副本管理。负责监控和维护集群中pod的副本(replicas)数,确保pod的副本数是我们期望的样子。使用 Deployment 时会自动创建 ReplicaSet,也就是说 Deployment 是通过 ReplicaSet 来管理 Pod 的多个副本,我们通常不需要直接使用 ReplicaSet,而是Deployment->ReplicaSet结合使用Deployment支持滚动更新但是滚动过程无序,新的ReplicaSet中的pod创建完毕后,再删除旧的,注意新的RepicaSet中的pod是随机创建的,不会按照旧的ReplicaSet中的pod顺序来,每创建一个新的就会删除旧的pod,所以这不利于有状态的服务,比如mysql主从,应该是先启动主后启动从

ps:蓝绿发布、滚动发布、灰度发布/金丝雀发布:https://zhuanlan.zhihu.com/p/42671353

1.3.3、DaemonSet 用于每个 Node 最多只运行一个 Pod 副本的场景。正如其名称所揭示的,DaemonSet 通常用于运行 daemon。

1.3.4、StatefuleSet 能够保证 Pod 的每个副本在整个生命周期中名称是不变的。而其他 Controller 不提供这个功能,当某个 Pod 发生故障需要删除并重新启动时,Pod 的名称会发生变化。同时 StatefuleSet 会保证副本按照固定的顺序启动、更新或者删除,这就非常利于有状态的服务,比如mysql主从

1.3.5、Job 用于运行结束就删除的应用。而其他 Controller 中的 Pod 通常是长期持续运行。

  • 1.4 服务Service 

Deployment 可以部署多个副本,每个 Pod 都有自己的 IP,外界如何访问这些副本呢?

通过 Pod 的 IP 吗?
要知道 Pod 很可能会被频繁地销毁和重启,它们的 IP 会发生变化,用 IP 来访问不太现实。

答案是 Service。
Kubernetes Service 定义了外界访问一组特定 Pod 的方式。Service 有自己的 IP 和端口,Service 为 Pod 提供了负载均衡。

Kubernetes 运行容器(Pod)与访问容器(Pod)这两项任务分别由 Controller 和 Service 执行。 

总结:Service是对应用的抽象,也是k8s中的基本操作单元,一个服务背后由多个pod支持,服务通过负载均衡策略将请求转发到容器中。

  • 1.5 Ingress
是一种网关服务,可以将服务Service通过http协议暴露到外部。
  • 1.6 无状态应用 & 有状态应用
#1、无状态应用
指的是应用在容器中运行时候不会在容器中持久化存储数据,应用容器可以随意创建、销毁;如果一个应用有多个容器实例,对于无状态应用,请求转发给任何一个容器实例都可以正确运行。例如:web应用
#2、有状态应用
指的是应用在容器中运行时候需要稳定的持久化存储、稳定的网络标识、固定的pod启动和停止次序。例如:mysql数据库
  • 1.7 Object
k8s 对象(Object)是一种持久化存储并且用于表示集群状态的实体。k8s 对象其实就是k8s自己的配置协议,总之我们可以通过定义一个object让k8s根据object定义执行一些部署任务、监控任务等等。
  • 1.8 Cluster 
Cluster 是计算、存储和网络资源的集合,Kubernetes 利用这些资源运行各种基于容器的应用。
具体点说,安装有kubelet组件的物理节点都属于cluster内节点,否则属于集群外节点,这个概念要搞清楚,很重要
  • 1.9 Namespace

如果有多个用户或项目组使用同一个 Kubernetes Cluster,如何将他们创建的 Controller、Pod 等资源分开呢?

答案就是 Namespace。
Namespace 可以将一个物理的 Cluster 逻辑上划分成多个虚拟 Cluster,每个 Cluster 就是一个 Namespace。不同 Namespace 里的资源是完全隔离的。

Kubernetes 默认创建了两个 Namespace。

[root@linux-node1 ~]# kubectl get namespace
NAME          STATUS    AGE
default       Active    1d
kube-system   Active    1d

default -- 创建资源时如果不指定,将被放到这个 Namespace 中。

kube-system -- Kubernetes 自己创建的系统资源将放到这个 Namespace 中。

  • 2.0 命名空间 (Namespace)

k8s命名空间主要用于隔离集群资源、隔离容器等,为集群提供了一种虚拟隔离的策略;默认存在3个名字空间,分别是默认命名空间 default、系统命名空间 kube-system 和 kube-public。

  • 2.1 Object

k8s 对象(Object)是一种持久化存储并且用于表示集群状态的实体。k8s 对象其实就是k8s自己的配置协议,总之我们可以通过定义一个object让k8s根据object定义执行一些部署任务、监控任务等等。

 

总结见附录:K8S核心组件和架构图

https://www.cnblogs.com/linhaifeng/articles/15160206.html

Ingress---》服务Service---》Pod

  • 2、Kubernetes架构和集群规划

  • (1)Kubernetes架构

 

 

  • (2)K8S架构拆解图

K8S Master节点

从上图可以看到,Master是K8S集群的核心部分,主要运行着以下的服务:kube-apiserver、kube-scheduler、kube-controller-manager、etcd和Pod网络(如:flannel)

API Server:K8S对外的唯一接口,提供HTTP/HTTPS RESTful API,即kubernetes API。所有的请求都需要经过这个接口进行通信,是唯一可以与etcd通信的组件。主要处理REST操作以及更新ETCD中的对象。是所有资源增删改查的唯一入口。 
Scheduler:资源调度,负责决定将Pod放到哪个Node上运行。Scheduler在调度时会对集群的结构进行分析,当前各个节点的负载,以及应用对高可用、性能等方面的需求。
Controller Manager:负责管理集群各种资源,保证资源处于预期的状态。Controller Manager由多种controller组成,包括replication controller、endpoints controller、namespace controller、serviceaccounts controller等
ETCD:负责保存k8s 集群的配置信息和各种资源的状态信息,当数据发生变化时,etcd会快速地通知k8s相关组件。

Pod网络:Pod要能够相互间通信,K8S集群必须部署Pod网络,flannel是其中一种的可选方案。

K8S Node节点

Node是Pod运行的地方,Kubernetes支持Docker、rkt等容器Runtime。Node上运行的K8S组件包括kubelet、kube-proxy和Pod网络。

Kubelet:kubelet是node的agent,当Scheduler确定在某个Node上运行Pod后,会将Pod的具体配置信息(image、volume等)发送给该节点的kubelet,kubelet会根据这些信息创建和运行容器,并向master报告运行状态。

Kube-proxy:service在逻辑上代表了后端的多个Pod,外借通过service访问Pod。service接收到请求就需要kube-proxy完成转发到Pod的。每个Node都会运行kube-proxy服务,负责将访问的service的TCP/UDP数据流转发到后端的容器,如果有多个副本,kube-proxy会实现负载均衡,有2种方式:LVS或者Iptables
Docker Engine:负责节点的容器的管理工作

Kubernetes中pod创建流程

  Pod是Kubernetes中最基本的部署调度单元,可以包含container,逻辑上表示某种应用的一个实例。例如一个web站点应用由前端、后端及数据库构建而成,这三个组件将运行在各自的容器中,那么我们可以创建包含三个container的pod。

具体的创建步骤包括:

(1)客户端提交创建请求,可以通过API Server的Restful API,也可以使用kubectl命令行工具。支持的数据类型包括JSON和YAML。

(2)API Server处理用户请求,存储Pod数据到etcd。

(3)调度器通过API Server查看未绑定的Pod。尝试为Pod分配主机。

(4)过滤主机 (调度预选):调度器用一组规则过滤掉不符合要求的主机。比如Pod指定了所需要的资源量,那么可用资源比Pod需要的资源量少的主机会被过滤掉。

(5)主机打分(调度优选):对第一步筛选出的符合要求的主机进行打分,在主机打分阶段,调度器会考虑一些整体优化策略,比如把容一个Replication Controller的副本分布到不同的主机上,使用最低负载的主机等。

(6)选择主机:选择打分最高的主机,进行binding操作,结果存储到etcd中。

(7)kubelet根据调度结果执行Pod创建操作: 绑定成功后,scheduler会调用APIServer的API在etcd中创建一个boundpod对象,描述在一个工作节点上绑定运行的所有pod信息。运行在每个工作节点上的kubelet也会定期与etcd同步boundpod信息,一旦发现应该在该工作节点上运行的boundpod对象没有更新,则调用Docker API创建并启动pod内的容器。

  • (3)实验环境准备:

如果是用虚拟机做实验,那么7台虚拟机都连接到NAT网络上

主机名                     IP地址             描述
linux-master01.example.com         eth0:10.1.1.100/24     K8S Master节点/ETCD节点,为了节省资源,同时部署haproxy+keepalived
linux-master02.example.com         eth0:10.1.1.101/24     K8S Master节点/ETCD节点,为了节省资源,同时部署haproxy+keepalived
linux-master03.example.com         eth0:10.1.1.102/24     K8s Master节点/ETCD节点

linux-node01.example.com           eth0:10.1.1.103/24     K8S 计算节点
linux-node02.example.com           eth0:10.1.1.104/24     K8S 计算节点
linux-node03.example.com           eth0:10.1.1.105/24     K8s 计算节点

linux-manager.example.com          eth0:10.1.1.106/24     用于运维管理的主机、ntp服务、部署docker私有仓库、k8s配置清单、nfs数据存储、证书签发
  • 7台vm,每台至少2g。
  • OS: CentOS 7.6.1810,升级后7.9
  • 内核:3.10
  • docker:v20.10.8
  • kubernetes:v1.17
  • etcd:v3.3.22
  • flannel:v0.12.0
  • harbor:v1.10
  • 证书签发工具CFSSL: R1.2
  • (4)系统环境初始化

1. 每台主机都关闭NetworkManager
systemctl stop NetworkManager
systemctl disable NetworkManager
2. 每台主机均关闭selinux与防火墙
sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/sysconfig/selinux
sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
setenforce 0
systemctl stop firewalld.service
systemctl disable firewalld.service
3. 每台主机规范主机名
hostnamectl set-hostname 主机名
4、每台机器升级操作系统并安装依赖包
yum install epel-release -y && yum update -y && yum upgrade -y && reboot

升级后需要重启计算机才能加载新内核,注意,一定要重启计算机

 # 升级前
 系统:CentOS Linux release 7.6.1810 (Core) 
 内核:3.10.0-957.el7.x86_64  
 ​
 # reboot 重启后
 系统:CentOS Linux release 7.9.2009 (Core)
 内核:3.10.0-1160.24.1.el7.x86_64  # 升级后
5、每台机器均安装常用软件
yum -y install python-setuptools python-pip gcc gcc-c++ autoconf libjpeg libjpeg-devel libpng libpng-devel freetype freetype-devel libxml2 libxml2-devel \
zlib zlib-devel glibc glibc-devel glib2 glib2-devel bzip2 bzip2-devel zip unzip ncurses ncurses-devel curl curl-devel e2fsprogs \
e2fsprogs-devel krb5-devel libidn libidn-devel openssl openssh openssl-devel nss_ldap openldap openldap-devel openldap-clients \
openldap-servers libxslt-devel libevent-devel ntp libtool-ltdl bison libtool vim-enhanced python wget lsof iptraf strace lrzsz \
kernel-devel kernel-headers pam-devel tcl tk cmake ncurses-devel bison setuptool popt-devel net-snmp screen perl-devel \
pcre-devel net-snmp screen tcpdump rsync sysstat man iptables sudo libconfig git  bind-utils \
tmux elinks numactl iftop bwm-ng net-tools expect
6、每台机器均修改ssh配置
加快远程链接速度,可选,但建议做

sed -ri '/#UseDNS yes/c UseDNS no' /etc/ssh/sshd_config
 ​
systemctl restart sshd
7、在管理节点添加hosts解析
cat >> /etc/hosts << EOF
10.1.1.100 master01
10.1.1.101 master02 
10.1.1.102 master03
10.1.1.103 node01
10.1.1.104 node02 
10.1.1.105 node03
10.1.1.106 manager
EOF
8、在管理节点10.1.1.106制作密钥登录所有其他节点
制作秘钥对
ssh-keygen 
 

在管理节点执行下述脚本(前提:目标主机的root密码均为1)

记得安装yum install expect -y
#!/bin/bash
for i in 'master01' 'master02' 'master03' 'node01' 'node02' 'node03' 'manager'
do
expect -c "
spawn ssh-copy-id -i root@$i
expect {
\"(yes/no)\" {send \"yes\r\";exp_continue}
\"password\" {send \"1\r\";exp_continue}
}
"
done
9、在管理节点10.1.1.106把/etc/hosts发给其他节点
#!/bin/bash
for i in 'master01' 'master02' 'master03' 'node01' 'node02' 'node03' 'manager'
do
    scp /etc/hosts root@$i:/etc/hosts
done
10、配置ntp服务,保证集群服务器时间统一

统一时间非常重要,必须要做

大前提:chrony服务端客户端配置完后,重启chronyd服务即可快速完成时间同步,在这之后就不要再手动去修改时间了,一切让时间服务器自己去同步

chrony服务端:manager节点

# 1、安装
yum -y install chrony

# 2、修改配置文件
mv /etc/chrony.conf /etc/chrony.conf.bak

cat > /etc/chrony.conf << EOF
server ntp1.aliyun.com iburst minpoll 4 maxpoll 10
server ntp2.aliyun.com iburst minpoll 4 maxpoll 10
server ntp3.aliyun.com iburst minpoll 4 maxpoll 10
server ntp4.aliyun.com iburst minpoll 4 maxpoll 10
server ntp5.aliyun.com iburst minpoll 4 maxpoll 10
server ntp6.aliyun.com iburst minpoll 4 maxpoll 10
server ntp7.aliyun.com iburst minpoll 4 maxpoll 10
driftfile /var/lib/chrony/drift
makestep 10 3
rtcsync
allow 0.0.0.0/0
local stratum 10
keyfile /etc/chrony.keys
logdir /var/log/chrony
stratumweight 0.05
noclientlog
logchange 0.5


EOF

# 4、启动chronyd服务
systemctl restart chronyd.service # 最好重启,这样无论原来是否启动都可以重新加载配置
systemctl enable chronyd.service
systemctl status chronyd.service

chrony客户端:其他节点,完全一样的配置与操作

# 下述步骤一次性粘贴到每个客户端执行即可
# 1、安装chrony
yum -y install chrony
# 2、需改客户端配置文件
mv /etc/chrony.conf /etc/chrony.conf.bak
cat > /etc/chrony.conf << EOF
server manager iburst
driftfile /var/lib/chrony/drift
makestep 10 3
rtcsync
local stratum 10
keyfile /etc/chrony.key
logdir /var/log/chrony
stratumweight 0.05
noclientlog
logchange 0.5

EOF # 3、启动chronyd systemctl restart chronyd.service systemctl enable chronyd.service systemctl status chronyd.service

# 4、验证
chronyc sources -v # 结果解析如下图

每一列的含义

 

 

11、在manager节点完成CA证书的创建和分发

从k8s的1.8版本开始,K8S系统各组件需要使用TLS证书对通信进行加密。每一个K8S集群都需要独立的CA证书体系。CA证书有以下三种:easyrsa、openssl、cfssl。这里使用cfssl证书,也是目前使用最多的,相对来说配置简单一些,通过json的格式,把证书相关的东西配置进去即可。这里使用cfssl的版本为1.2版本。

 12、在manager节点执行下述命令,远程为所有节点创建工作目录
#!/bin/bash
for i in 'master01' 'master02' 'master03' 'node01' 'node02' 'node03' 'manager'
do
    ssh root@$i 'mkdir -p /opt/kubernetes/{cfg,bin,ssl,log}'
    echo "$i ok"
done
13、在所有节点执行下述命令,完成环境变量配置
echo 'PATH=$PATH:$HOME/bin:/opt/kubernetes/bin' >> /root/.bash_profile
source /root/.bash_profile
14、安装docker

在manager、node01、node02、node3上部署docker,因为mananger上要基于docker启镜像仓库,所以也需要安装docker

# 第一步:使用国内Docker源
cd /etc/yum.repos.d/
wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

# 第二步:Docker安装:
yum install -y docker-ce

# 第三步:修改配置文件
mkdir -p /data/docker
mkdir -p /etc/docker cat
> /etc/docker/daemon.json << EOF { "graph": "/data/docker", "storage-driver": "overlay", "insecure-registries": ["registry.access.redhat.com","quay.io"], "bip": "172.168.10.1/24", "registry-mirrors": ["https://l2v84zex.mirror.aliyuncs.com"], "exec-opts": ["native.cgroupdriver=systemd"], "live-restore": true } EOF # 第三步:启动后台进程 systemctl start docker systemctl enable docker systemctl status docker
15、在manager节点部署docker镜像私有仓库harbor
#1、下载
wget https://github.com/goharbor/harbor/releases/download/v2.3.1/harbor-offline-installer-v2.3.1.tgz

tar xf harbor-offline-installer-v2.3.1.tgz -C /opt
mv /opt/harbor /opt/harbor-v2.3.1
ln -s /opt/harbor-v2.3.1 /opt/harbor

#2、配置
cp /opt/harbor/harbor.yml.tmpl /opt/harbor/harbor.yml
vim /opt/harbor/harbor.yml
# 修改第5行hostname为manager的ip
hostname = 10.1.1.106

#3、第7到18行,harbor启用http和https协议,指定证书路径,如果是实验环境也可以直接注释掉7到18行
http:
  port: 180

#https:
#  port: 443
#  certificate: /opt/kubernetes/ssl/
#  private_key: /opt/kubernetes/ssl/
  

# 第34行,habor的管理员密码
harbor_admin_password: Harbor12345

# 第47行,harbor的数据存储位置
data_volume: /data

 
#4、安装docker-compose,下面的安装脚本需要它
yum install docker-compose -y
 
#5、 安装启动
cd /opt/harbor
./install.sh 
docker-compose ps


#6、重启Harbor,因为Harbor是基于docker-compose服务编排的,所以通过 docker-compose启动或者关闭Harbor
docker-compose down
docker-compose up -d

#7、安装nginx对80端口进行反代,---->监听8888端口,防止跟后续端口冲突,比如apiserver的8080
yum -y install nginx

cat > /etc/nginx/conf.d/harbor.od.com.conf << EOF
server {
    listen       8888;
    server_name  localhost;

    client_max_body_size 1000m;

    location / {
        proxy_pass http://127.0.0.1:180;
    }
}

EOF

systemctl restart nginx

### https协议可选,此处我们就忽略了
server {
    listen       443 ssl;
    server_name  harbor.od.com;

    ssl_certificate "certs/harbor.od.com.pem";
    ssl_certificate_key "certs/harbor.od.com-key.pem";
    ssl_session_cache shared:SSL:1m;
    ssl_session_timeout  10m;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;
    client_max_body_size 1000m;

    location / {
        proxy_pass http://127.0.0.1:180;
    }
}

自签证书
openssl genrsa -out od.key 2048
openssl req -new -key od.key -out od.csr -subj "/CN=*.od.com/ST=Beijing/L=beijing/O=od/OU=ops"
openssl x509 -req -in od.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out od.crt -days 365


#8、然后在浏览器上,输入服务器ip地址,打开harbor登录界面。默认用户名是admin,密码就是在harbor.yml里配置的密码Harbor12345
10.1.1.106:8888

一个简单的harbor就部署完成。

#9、从docker.io上下载镜像,然后推送到自己的私有仓库
先在habor的web界面里创建好仓库,名为egonlin
docker pull nginx docker image ls docker image tag nginx 10.1.1.106:8888/egonlin/nginx:v_new docker login 10.1.1.106:8888 docker push 10.1.1.106:8888/egonlin/nginx:v_new
16、在所有安装docker的节点上修改配置,增加habor仓库地址
cat > /etc/docker/daemon.json << EOF
{
  "graph": "/data/docker",
  "storage-driver": "overlay",
  "insecure-registries": ["registry.access.redhat.com","quay.io","10.1.1.106:8080"],
  "bip": "172.168.10.1/24",
  "registry-mirrors": ["https://l2v84zex.mirror.aliyuncs.com"],
  "exec-opts": ["native.cgroupdriver=systemd"],
  "live-restore": true
}

EOF

systemctl restart docker

 

posted @ 2021-08-19 10:13  linhaifeng  阅读(2645)  评论(0编辑  收藏  举报