一、Kubernetes概述
1.1 Kubernetes介绍
1.1.1 Kubernetes是什么及作用
Kubernetes(K8S)用于自动化容器化应用程序的部署、扩展和管理
Kubernetes通常结合docker容器工作,并且整合多个运行着docker容器的主机集群。
官网地址:https://Kubernetes.io
中文社区:https://www.kubernetes.org.cn/docs
Kubernetes的目标是让部署容器化的应用简单并且高效,Kubernetes一个核心特点就是能够自主的管理容器来保证云平台中的容器按照用户的期望运行
以下是Kubernetes相关特性:
-
自动包装
根据资源需求和其他约束自动放置容器,同时不会牺牲可用性,混合关键和最大努力的工作负载,以提高资源利用率并节省更多资源
-
横向缩放
使用简单的命令或UI,或者根据CPU的使用情况自动调整应用程序副本数
-
自动部署和回滚
Kubernetes逐渐部署对应用程序或其配置的更改,同时监视应用程序运行状况,以确保它不会同时终止所有实例,如果出现问题,Kubernetes会恢复更改,利用日益增长的部署解决方案的生态系统
-
存储编排
自动安装所选择的存储系统,无论是本地存储,如公有云提供商GCP或AWS,还是网络存储系统NFS,iSCSI,Gluster,Ceph,Cinder或Flocker
-
自我修复
重新启动失败的容器,在节点不可用时,替换和重新编排节点上的容器,终止不对用户定义的健康检查做响应的容器,并且不会再客户端准备投放之前将其通告给客户端
-
服务发现和负载均衡
不需要修改应用程序来使用不熟悉的服务发现机制,kubernetes为容器提供了自己的ip地址和一组容器的单个DNS名称,并可以在他们之间进行负载均衡
-
密钥和配置管理
部署和更新密钥和应用程序配置吗,不会重新编译你的景象,不会在堆栈配置中暴露密钥(secrets)
-
批处理
除了服务之外,kubernetes还可以管理批处理和CI工作负载,如果需要,替换出现故障的容器
使用kubernetes能做什么
kubernetes是一个全新的基于容器技术的分布式架构领先方案
kubernetes是一个开放的开发平台(无侵入性,现有系统容器迁移到kubernetes上),是一个晚辈的分布式系统支撑平台(完善的集群管理能力)
使用Kubernetes可以在物理或虚拟机的kubernets集群上运行容器化应用,Kubernetes能够提供一个以容器为中心的基础架构,满足在生产环境中运行应用的一些常见需求,如:
- 多个进程协同工作
- 存储系统挂在
- Distributing secrets
- 应用健康监测
- 应用实例的复制
- Pod自动伸缩/扩展
- Naming and discovering
- 负载均衡
- 滚动更新
- 资源监控
- 日志访问
- 调度应用程序
- 提供认证和授权
为什么使用Kubernetes
使用Kubernetes最直接的感受就是我们可以轻装上阵的开发复杂的系统了
其次Kubernetes是在全面拥抱微服务架构(微服务的核心就是将一个巨大的单体应用拆分成很多小的互相连接的微服务,一个微服务后面可能是多个实例副本在支撑,副本数量可以随着系统负荷的变化而动态调整)
最后Kubernetes系统架构具备超强的横向扩展能力
1.1.2 Kubernetes快速入门
-
环境准备
-
关闭Centos防火墙
systemctl disable firewalld
systemctl stop firewalld
-
安装etcd和Kubernetes软件
yum update
yum install -y etcd kubernetes
-
启动服务
systemctl start etcd
systemctl start docker
如果docker启动失败,请参考(vi /etc/sysconfig/selinux 把selinux后面的改为disabled,重启一波机器,再重启docker就可以了)
systemctl start kube-apiserver
systemctl start kube-controller-manager
systemctl start kube-scheduler
systemctl start kubelet
systemctl start kube-proxy
-
-
配置
-
安装本地私有仓库
docker pull registry
docker run -di -p 5000:5000 registry
添加仓库信任
vi /etc/docker/daemon.json
{
“registry-mirrors”:[“https://docker.mirrors.ustc.edu.cn”], #这里是添加国内镜像加速仓库
“insecure-registries”:[“192.168.65.133:5000”] #添加私有仓库信任,用于pull和push镜像
}systemctl daemon-reload
systemctl restart docker
访问
http://192.168.65.133:5000/v2/_catalog
-
Tomcat配置
mkdir -p /usr/local/k8s
cd /usr/local/k8s
-
mytomcat.rc.yaml
apiVersion: v1 kind: ReplicationController metadata: name: mytomcat spec: replicas: 2 selector: app: mytomcat template: metadata: labels: app: mytomcat spec: containers: - name: mytomcat image: tomcat:7-jre7 ports: - containerPort: 8080
kubectl create -f mytomcat.rc.yaml
-
mytomcat.svc.yaml
apiVersion: v1 kind: Service metadata: name: mytomcat spec: type: NodePort ports: - port: 8080 nodePort: 30001 selector: app: mytomcat
kubectl create -f mytomcat.svc.yaml
kubectl get svc
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes 10.254.0.1 <none> 443/TCP 6m mytomcat 10.254.119.243 <nodes> 8080:30001/TCP 14s
kubectl get pods(如下是有问题的,解决方案在下面)
No resources found
正常的显示如下(但是未启动,解决方案在下面)
NAME READY STATUS RESTARTS AGE mytomcat-cqbfh 0/1 ContainerCreating 0 7s mytomcat-tnbjb 0/1 ContainerCreating 0 7s
-
-
-
问题解决
-
docker pull失败
-
解决方案1
1、yum install -y rhsm
2、docker search pod-infrastructure
3、docker pull docker.io/tianyebj/pod-infrastructure
4、docker tag tianyebj/pod-infrastructure 192.168.65.133:5000/pod-infrastructure
5、docker push 192.168.65.133:5000/pod-infrastructure
6、vi /etc/kubernetes/kubelet
修改KUBELET_POD_INFRA_CONTAINER="–pod-infra-container-image=192.168.65.133:5000/pod-infrastructure:latest"
7、重启服务
systemctl restart kube-apiserver
systemctl restart kube-controller-manager
systemctl restart kube-scheduler
systemctl restart kubelet
systemctl restart kube-proxy
-
解决方案2
1、docker pull docker.io/kubernetes/pause
2、docker tag docker.io/kubernetes/pause:latest 192.168.65.133:5000/google_containers/pause-amd64.3.0
3、docker push 192.168.65.133:5000/google_containers/pause-amd64.3.0
4、vi /etc/kubernetes/kubelet
KUBELET_ARGS="–pod_infra_container_image=192.168.65.133:5000/google_containers/pause-amd64.3.0"
5、重启kubelet服务
systemctl restart kubelet
-
-
外部网络不能访问
在搭建好的k8s集群内创建的容器,只能在其所在的节点上curl可访问,但是在其他任何主机上无法访问容器占用的端口
解决方案:
1、vim /etc/sysctl.conf
2、net.ipv4.ip_forward=1
3、cd /usr/local/k8s
4、kubectl replace -f mytomcat.rc.yaml
5、kubectl delete svc --all
6、kubectl create -f mytomcat.svc.yaml
7、防火墙端口开放
systemctl start firewalld firewall-cmd --list-ports firewall-cmd --state firewall-cmd --zone=public --add-port=30001/tcp --permanent firewall-cmd --reload systemctl stop firewalld
-
解决kubectl get pods时No resources found问题
1、vim /etc/kubernetes/apiserver
2、找到 KUBE_ADMISSION_CONTROL="–admission-control=NamespaceLifecycle,NamespaceExists,LimitRanger,SecurityContextDeny,ServiceAccount,ResourceQuota",去掉ServiceAccount,保存退出
3、systemctl restart kube-apiserver
-
-
浏览测试
http://192.168.65.133:30001
1.2 Kubernetes基本架构与常用术语
Kubernetes集群包含有节点代理Kubelet和Master组件(APIs,scheduler,etc),一切都基于分布式的存储系统。
下面这张图是Kubernetes的架构图
在这张系统架构图中,把服务分为运行在工作节点上的服务和组成集群级别控制板的服务
Kubernetes节点有运行应用容器必备的服务,而这些都是受Master的控制
每个节点上都要运行Docker,Docker来负责所有具体的镜像下载和容器运行
Kubernetes主要有以下几个核心组件组成:
- etcd:保存了整个集群的状态
- apiserver:提供了资源操作的唯一入口,并提供认证、授权、访问控制、API注册和发现等机制
- controller manger:负责维护集群的状态,比如故障检测、自动扩展、滚动更新等
- schuduler:负责资源的调度,按照预定的调度策略将Pod调度到相应的机器上
- kubelet:负责维护容器的生命周期,同时也负责Volume(CVI)和网络(CNI)的管理
- Container runtime:负责镜像管理以及Pod和容器的真正运行(CRI)
- kube-proxy:负责为Service提供cluster内部的服务发现和负载均衡
除了核心组件,还有一些推荐的Add-ons:
- kube-dns:负责为整个集群提供DNS服务
- Ingress Controller:微服务提供外网接口
- Heapster:提供资源架空
- Dashboard:提供GUI
- Federation:提供跨可用区的集群
- Fluentd-elasticsearch:提供集群日志采集、存储和查询
Kubernetes设计理念和功能其实就是一个类似Linux的分层架构
- 核心层:Kubernetes最核心的功能,对外提供API构建高层的应用,对内提供插件式应用执行环境
- 应用层:部署(无状态应用、有状态应用、批处理任务、集群应用等)和路由(服务发现、DNS解析等)
- 管理层:系统度量(如基础设施、容器和网络的度量),自动化(如自动扩展、动态Provision等)以及策略管理(RBAC、Quota、PSP、NetworkPolicy等)
- 接口层:kubectl命令行工具、客户端SDK以及集群联邦
- 生态系统:在接口层之上的庞大容器集群管理调度的生态系统,可以划分为两个范畴
- Kubernetes外部:日志、监控、配置管理、CI、CD、Workflow、Faas、OTS应用、ChatOps等
- Kubernetes内部:CRI、CNI、CVI、镜像仓库、Cloud Provider、集群自身的配置和管理等
1.2.1 Cluster
Cluster是计算、存储和网络资源的集合,Kubernetes利用这些资源运行各种基于容器的应用
Kubernetes Cluster由Master和Node组成,节点上运行着若干Kubernets服务
1.2.2 Master
Master主要职责是调度,即决定将应用放在那里去执行。
Master运行Linux系统,可以是物理机或虚拟机
Master是Kubernetes Cluster的大脑,运行着Daemon服务包括kube-apiserver、kube-scheduler、kube-controller-manager、etcd和Pod网络
-
API Server(kube-apiserver)
API Server提供HTTP/HTTPS RESTful API,即Kubernetes API。是Kubernets里所有资源的CRUD等操作的唯一入口,也是集群控制的入口进程
-
Scheduler(kube-scheduler)
Scheduler是负责资源调度的进程,它决定将Pod放在哪个Node上运行
-
Controller Manager(kube-controller-manager)
所有资源对象的自动化控制中心。Controller Manager负责管理Cluster的各种资源,保证资源处于预期的状态
Controller Manager有多种,如replication controller、endpoints controller、namespace controller、serviceaccount controller等
不同的controller管理不同的资源,如replication controller管理Deployment、StatefulSet、DaemonSet的声明周期,namespace controller管理Namespace资源
-
etcd
etcd负责保存Kubernetes Cluster的配置信息和各种资源的状态信息。当数据发生变化时,etcd会快速地通知Kubernets相关组件
-
Pod网络
Pod要能够相互通信,Kubernetes Cluster必须部署Pod网络,flannel是其中一个可选方案
1.2.3 Node
除了Master,Kubernetes集群中的其他机器被称为Node节点。Node职责是运行容器应用,Node由Master管理,Node负责监控并汇报容器的状态,同时根据Master的要求管理容器的生命周期
Node也运行在Linux系统,可以是物理机或虚拟机
每个Node节点上都运行着以下一组关键进程
-
kubelet
负责Pod对应的容器的创建、启动等任务,同时与Master节点密切协作,实现集群管理的基本功能
-
kube-proxy
实现Kubernetes Service的通信与负载均衡机制的重要组件
-
Docker Enginer
Docker引擎,负责本机的容器创建和管理工作
1.2.4 Pod
Pod是Kubernetes的最小单元,也是最重要和最基本的概念。
每一个Pod包含一个或多个容器,Pod的容器会作为一个整体被Master调度到一个Node上运行
Kubernetes为每个Pod都分配了唯一的IP地址,称为Pod IP
一个Pod里的多个容器共享Pod IP地址
在Kubernetes里,一个Pod里的容器与另外主机上的Pod容器能够直接通信
1.2.5 Service
Kubernetes Service定义了外界访问一组特定Pod的方式,Service有自己的ip和端口,Service提供了负载均衡。
也是Kubernetes最核心的资源对象之一,每个Service其实就是我们经常提起的微服务架构的一个“微服务”
1.2.6 Replication Controller
Replication Controller(简称RC)是Kubernetes系统中的核心概念之一,它其实是定义了一个期望的场景,即声明某种Pod的副本数量在任意时刻都符合某个预期值,所有RC的定义包括如下几个部分
- Pod期待的副本数(replicas)
- 用于筛选目标Pod的Lable Selector
- 当Pod的副本数量小于预期数量时,用于创建新Pod的Pod模板(template)
以下是总结的RC的一些特性与作用
-
在大多数情况下,我们通过定义一个RC实现Pod的创建过程及副本数量的自动控制
-
RC里包括完成的Pod定义模板
-
RC通过Label Selector机制实现对Pod副本的自动控制
-
通过改变RC里的Pod副本数量,可以实现Pod的扩容和缩容功能
-
通过改变RC里的Pod模板中镜像版本,可以实现Pod的滚动升级功能
二、Kubernetes集群
Kubernetes用于协调高度可用的计算机集群吗,这些计算机群集被连接作为单个单元工作。
Kubernetes在一个集群上以更有效的方式自动分发和调度容器应用程序。
Kubernetes集群由两种类型的资源组成:
Master是集群的调度节点
Nodes是应用程序实际运行的工作节点
K8S集群部署有几种方式:kubeadm、minikube和二进制包
前两者属于自动部署,简化部署操作,
推荐使用二进制包部署,因为自动部署屏蔽了很多细节,使得对各个某块感知很少
安装需要的包在 https://download.csdn.net/download/snow_hope/16464841 进行下载
部署环境要求
(1)一台或多台机器,操作系统CentOS 7.x-86_x64
(2)硬件配置:内存2GB或2G+,CPU 2核或CPU 2核+;
(3)集群内各个机器之间能相互通信;
(4)集群内各个机器可以访问外网,需要拉取镜像;
(5)禁止swap分区;
2.二进制包安装
2.1 环境装备与规划
-
推荐配置2核2G
Docker version 17.05.0-ce
角色 IP 组件 master 192.168.65.137 etcd、kube-apiserver、kube-controller-manager、kube-scheduler、docker node01 192.168.65.138 kube-proxy、kubelet、docker node02 192.168.65.139 kube-proxy、kubelet、docker -
查看默认防火墙状态(关闭后显示not running,开启后显示running)
firewall-cmd --state
-
关闭防火墙
systemctl stop firewalld
-
禁止firewalld开机启动
systemctl disable firewalld
-
获取Kubernetes二进制包
kubernetes-server-linux-amd64.tar.gz
-
将二进制包上传到/opt/software
2.2 Master安装
2.2.1 Docker安装
(1)修改配置
vi /etc/sysconfig/selinux
SELINUX=disabled
重启机器
reboot
(2)安装docker
yum install docker -y
docker -v
(3)配置国内镜像
vi /etc/docker/daemon.json
{
"registry-mirrors":["https://docker.mirrors.ustc.edu.cn"]
}
(4)安装docker-compose
下载
sudo curl -L https://get.daocloud.io/docker/compose/releases/download/1.25.1/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
上层文件中已有包
sudo chmod +x /usr/local/bin/docker-compose
docker-compose --version
2.2.2 etcd服务
etcd作为Kubernetes集群的主要服务,在安装Kubernetes各服务前首先安装和启动
-
获取二进制文件
etcd-v3.3.4-linux-amd64.tar.gz
-
上传到master的/opt/software目录
-
解压
cd /opt/software
tar -zxvf etcd-v3.3.4-linux-amd64.tar.gz
-
将etcd和etcdctl文件复制到/usr/bin
-
配置systemd服务文件/usr/lib/systemd/system/etcd.service
[Unit] Description=Etcd Server After=network.target [Service] Type=simple EnvironmentFile=-/etc/etcd/etcd.conf WorkingDirectory=/var/lib/etcd ExecStart=/usr/bin/etcd Restart=on-failure [Install] WantedBy=multi-user.target
-
启动与测试etcd服务
mkdir -p /var/lib/etcd systemctl daemon-reload systemctl enable etcd.service systemctl start etcd.service etcdctl cluster-health
2.2.3 kube-apiserver服务
解压
cd /opt/software
tar -zxvf kubernetes-server-linux-amd64.tar.gz
解压后将kube-apiserver、kube-controller-manager、kube-scheduler以及管理要使用的kubectl二进制命令文件放到/usr/bin目录,即完成这几个服务的安装
cp kube-apiserver kube-controller-manager kube-scheduler kubectl /usr/bin
下面是对kube-apiserver服务进行配置
编辑systemd服务文件:vi /usr/lib/systemd/system/kube-apiserver.service
[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/kubernetes/kubernetes
After=etcd.service
Wants=etcd.service
[Service]
EnvironmentFile=-/etc/kubernetes/apiserver
ExecStart=/usr/bin/kube-apiserver $KUBE_API_ARGS
Restart=on-failure
Type=notify
[Install]
WantedBy=multi-user.target
配置文件
创建目录:mkdir /etc/kubernetes
vi /etc/kubernetes/apiserver
KUBE_API_ARGS="--storage-backend=etcd3 --etcd-servers=http://127.0.0.1:2379 --insecure-bind-address=0.0.0.0 --insecure-port=8080 --service-cluster-ip-range=169.169.0.0/16 --service-node-port-range=1-65535 --admission-control=NamespaceLifecycle,NamespaceExists,LimitRanger,SecurityContextDeny,ServiceAccount,DefaultStorageClass,ResourceQuota --logtostderr=true --log-dir=/var/log/kubernetes --v=2"
2.2.4 kube-controller-manager服务
kube-controller-manager服务依赖于kube-apiserver服务:
配置systemd服务文件:vi /usr/lib/systemd/system/kube-controller-manager.service
[Unit]
Description=Kubernetes Controller Manager
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=kube-apiserver.service
Requires=kube-apiserver.service
[Service]
EnvironmentFile=-/etc/kubernetes/controller-manager
ExecStart=/usr/bin/kube-controller-manager $KUBE_CONTROLLER_MANAGER_ARGS
Restart=on-failure
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
配置文件:vi /etc/kubernetes/controller-manager
KUBE_CONTROLLER_MANAGER_ARGS="--master=192.168.65.137:8080 --logtostderr=true --log-dir=/var/log/kubernetes --v=2"
2.2.5 kube-scheduler服务
kube-scheduler服务也依赖于kube-apiserver服务
配置systemd服务文件:vi /usr/lib/systemd/system/kube-scheduler.service
[Unit]
Description=Kubernetes scheduler
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=kube-apiserver.service
Requires=kube-apiserver.service
[Service]
EnvironmentFile=-/etc/kubernetes/scheduler
ExecStart=/usr/bin/kube-scheduler $KUBE_scheduler_ARGS
Restart=on-failure
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
配置文件:vi /etc/kubernetes/scheduler
KUBE_scheduler_ARGS="--master=192.168.65.137:8080 --logtostderr=true --log-dir=/var/log/kubernetes --v=2"
2.2.6 启动
完成以上配置后,按顺序启动服务
systemctl daemon-reload
systemctl enable kube-apiserver.service
systemctl start kube-apiserver.service
systemctl enable kube-controller-manager.service
systemctl start kube-controller-manager.service
systemctl enable kube-scheduler.service
systemctl start kube-scheduler.service
检查每个服务的健康状态:
systemctl status kube-apiserver.service
systemctl status kube-controller-manager.service
systemctl status kube-scheduler.service
2.2.7 Node节点安装准备
scp -r kubernetes 192.168.65.138:/opt/software/kubernetes
scp -r kubernetes 192.168.65.139:/opt/software/kubernetes
2.3 Node1安装
在Node1节点上,以同样的方式把从压缩包中解压出来的二进制文件kubelet kube-proxy放到/usr/bin目录中,见步骤 2.2.7
cd /opt/software/kubernetes/server/bin
cp kubelet kube-proxy /usr/bin
vi /etc/fstab
注释掉 /dev/mapper/centos-swap swap
#/dev/mapper/centos-swap swap swap defaults 0 0
在Node1节点上需要预先安装docker,请参考Master上docker的安装,并启动Docker
2.3.1 kubelet服务
配置systemd服务文件:vi /usr/lib/systemd/system/kubelet.service
[Unit]
Description=Kubernetes Kubelet Server
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=docker.service
Requires=docker.service
[Service]
WorkingDirectory=/var/lib/kubelet
EnvironmentFile=-/etc/kubernetes/kubelet
ExecStart=/usr/bin/kubelet $KUBELET_ARGS
Restart=on-failure
KillMode=process
[Install]
WantedBy=multi-user.target
创建目录:mkdir -p /var/lib/kubelet
mkdir /etc/kubernetes
配置文件:vi /etc/kubernetes/kubelet
KUBELET_ARGS="--kubeconfig=/etc/kubernetes/kubeconfig --hostname-override=192.168.65.138 --cgroup-driver=systemd --logtostderr=false --log-dir=/var/log/kubernetes --v=2 --fail-swap-on=false"
用于kubelet连接Master Apiserver的配置文件
vi /etc/kubernetes/kubeconfig
apiVersion: v1
kind: Config
clusters:
- cluster:
server: http://192.168.65.137:8080
name: local
contexts:
- context:
cluster: local
name: mycontext
current-context: mycontext
2.3.2 kube-proxy服务
kube-proxy服务依赖于network服务,所以一定要保证network服务正常,如果network服务启动失败,常见解决方案有以下几种:
1.和NetworkManger服务有冲突,直接关闭NetworkMnager服务就好了,service NetworkManager stop,并且禁止开机启动 chkconfig NetworkManager off,之后重启就好了
2.和配置文件的MAC地址不匹配,使用 ip addr(或 ifconfig)查看MAC地址,将/etc/sysconfig/network-scripts/ifcfg-xxx中的HWADDR改为查看到的MAC地址
3.设定卡机启动一个名为NetworkManager-wait-online服务,命令为
systemctl enable NetworkManager-wait-online.service
4.查看/etc/sysconfig/network-scripts下,将其余无关的网卡位置文件全删掉,避免不必要的影响,即只保留一个以ifcfg开头的文件
配置systemd服务文件:vi /usr/lib/systemd/system/kube-proxy.service
[Unit]
Description=Kubernetes Kube-proxy Server
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=network.service
Requires=network.service
[Service]
EnvironmentFile=-/etc/kubernetes/proxy
ExecStart=/usr/bin/kube-proxy $KUBE_PROXY_ARGS
Restart=on-failure
killMode=process
[Install]
WantedBy=multi-user.target
配置文件:vi /etc/kubernetes/proxy
KUBE_PROXY_ARGS="--master=http://192.168.65.137:8080 --hostname-override=192.168.65.138 --logtostderr=true --log-dir=/var/log/kubernetes --v=2"
2.3.3 启动
systemctl daemon-reload
systemctl enable kubelet
systemctl start kubelet
systemctl status kubelet
systemctl enable kube-proxy
systemctl start kube-proxy
systemctl status kube-proxy
2.4 Node2安装
参考Node1节点安装,注意修改IP
2.5 健康检查与示例测试
-
查看集群状态
kubelctl get nodes NAME STATUS ROLES AGE VERSION 192.168.65.138 Ready <none> 8m40s v1.19.7 192.168.65.139 Ready <none> 2m8s v1.19.7
-
查看master集群组件状态
kubectl get cs Warning: v1 ComponentStatus is deprecated in v1.19+ NAME STATUS MESSAGE ERROR etcd-0 Healthy {"health":"true"} controller-manager Healthy ok scheduler Healthy ok
-
nginx-rc.yaml
mkdir /usr/local/k8s
cd /usr/local/k8s
vi nginx-rc.yaml
apiVersion: v1 kind: ReplicationController metadata: name: nginx spec: replicas: 3 selector: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx ports: - containerPort: 80
kubectl create -f nginx-rc.yaml
-
nginx-svc.yaml
apiVersion: v1 kind: Service metadata: name: nginx spec: type: NodePort ports: - port: 80 nodePort: 33333 selector: app: nginx
kubectl create -f nginx-svc.yaml
-
查看Pod
kubectl get pods No resources found in default namespace. 问题解决方案: 原因是docker拉取镜像失败 通过搭建私有仓库方式:docker pull registry docker run -di --name=registry -p 5000:5000 registry 修改daemon.json vi /etc/docker/daemon.json { "registry-mirrors":["https://docker.mirrors.ustc.edu.cn"], "insecure-registries":["192.168.65.137:5000"] } docker pull docker.io/kubernetes/pause docker tag docker.io/kubernetes/pause:latest 192.168.65.137:5000/google_containers/pause-amd64.3.0 docker push 192.168.65.137:5000/google_containers/pause-amd64.3.0 修改node节点上的kubelete vi /etc/kubernetes/kubelet KUBELET_ARGS="--pod_infra_container_image=192.168.65.137:5000/google_containers/pause-amd64.3.0 --kubeconfig=/etc/kubernetes/kubeconfig --hostname-override=192.168.65.138 --cgroup-driver=systemd --logtostderr=false --log-dir=/var/log/kubernetes --v=2 --fail-swap-on=false" 重启kubelet服务 systemctl restart kubelet kubectl replace -f nginx-rc.yaml kubectl delete svc --all kubectl create -f nginx-svc.yaml kubectl get pods NAME READY STATUS RESTARTS AGE nginx-5wqlx 1/1 Running 0 2m21s nginx-c54lc 1/1 Running 0 2m21s nginx-n9pbm 1/1 Running 0 2m21s
3.Kubeadm安装
3.1 环境装备与规划
-
推荐配置2核2G
Docker version 17.05.0-ce
角色 IP 组件 k8smaster 192.168.65.133 etcd、kube-apiserver、kube-controller-manager、kube-scheduler、docker k8snode1 192.168.65.136 kube-proxy、kubelet、docker k8snode2 192.168.65.140 kube-proxy、kubelet、docker -
查看默认防火墙状态(关闭后显示not running,开启后显示running)
firewall-cmd --state
-
关闭防火墙
systemctl stop firewalld
systemctl disable firewalld
-
关闭selinux
sed -i ‘s/enforcing/disabled/’ /etc/selinux/config #永久
setenforce 0 #临时
-
关闭swap(k8s禁止虚拟内存以提高性能)
sed -ri ‘s/.swap./#&/’ /etc/fstab #永久
swapoff -a #临时
-
在master添加hosts
cat >> /etc/hosts << EOF
192.168.65.133 k8smaster
192.168.65.136 k8snode1
192.168.65.140 k8snode2
EOF
-
设置网桥参数
cat > /etc/sysctl.d/k8s.conf << EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sysctl --system #生效
-
时间同步
yum install ntpdate -y
ntpdate time.windows.com
所有服务器节点安装 Docker/kubeadm/kubelet/kubectl
Kubernetes 默认容器运行环境是Docker,因此首先需要安装Docker;
3.2 安装Docker
(1)修改配置
vi /etc/sysconfig/selinux
SELINUX=disabled
重启机器
reboot
(2)安装docker
yum install docker -y
docker -v
(3)配置国内镜像
vi /etc/docker/daemon.json
{
"registry-mirrors":["https://docker.mirrors.ustc.edu.cn"]
}
(4)安装docker-compose
下载
sudo curl -L https://get.daocloud.io/docker/compose/releases/download/1.25.1/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
上层文件中已有包
sudo chmod +x /usr/local/bin/docker-compose
docker-compose --version
(5)启动docker
systemctl start docker
systemctl enable docker
3.3 安装kubeadm、kubelet、kubectl
(1)添加k8s的阿里云YUM源,到时候下载k8s的相关组件才能找到下载源;
cat > /etc/yum.repos.d/kubernetes.repo << EOF
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
(2)安装 kubeadm,kubelet 和 kubectl
Kubelet:运行在cluster所有节点上,负责启动POD和容器;
Kubeadm:用于初始化cluster的一个工具;
Kubectl:kubectl是kubenetes命令行工具,通过kubectl可以部署和管理应用,查看各种资源,创建,删除和更新组件;
yum install kubelet-1.19.4 kubeadm-1.19.4 kubectl-1.19.4 -y
systemctl enable kubelet.service
查看有没有安装:
yum list installed | grep kubelet
yum list installed | grep kubeadm
yum list installed | grep kubectl
查看安装的版本: kubelet --version
(3) 重启机器
(4)部署Kubernetes Master主节点(主节点上执行)
kubeadm init --apiserver-advertise-address=192.168.65.133 --image-repository registry.aliyuncs.com/google_containers --kubernetes-version v1.19.4 --service-cidr=10.96.0.0/12 --pod-network-cidr=10.244.0.0/16
输出结果:
0402 05:10:40.940464 2510 configset.go:348] WARNING: kubeadm cannot validate component configs for API groups [kubelet.config.k8s.io kubeproxy.config.k8s.io]
[init] Using Kubernetes version: v1.19.4
[preflight] Running pre-flight checks
[WARNING SystemVerification]: missing optional cgroups: pids
[preflight] Pulling images required for setting up a Kubernetes cluster
[preflight] This might take a minute or two, depending on the speed of your internet connection
[preflight] You can also perform this action in beforehand using 'kubeadm config images pull'
[certs] Using certificateDir folder "/etc/kubernetes/pki"
[certs] Generating "ca" certificate and key
[certs] Generating "apiserver" certificate and key
[certs] apiserver serving cert is signed for DNS names [k8smaster kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local] and IPs [10.96.0.1 192.168.65.133]
[certs] Generating "apiserver-kubelet-client" certificate and key
[certs] Generating "front-proxy-ca" certificate and key
[certs] Generating "front-proxy-client" certificate and key
[certs] Generating "etcd/ca" certificate and key
[certs] Generating "etcd/server" certificate and key
[certs] etcd/server serving cert is signed for DNS names [k8smaster localhost] and IPs [192.168.65.133 127.0.0.1 ::1]
[certs] Generating "etcd/peer" certificate and key
[certs] etcd/peer serving cert is signed for DNS names [k8smaster localhost] and IPs [192.168.65.133 127.0.0.1 ::1]
[certs] Generating "etcd/healthcheck-client" certificate and key
[certs] Generating "apiserver-etcd-client" certificate and key
[certs] Generating "sa" key and public key
[kubeconfig] Using kubeconfig folder "/etc/kubernetes"
[kubeconfig] Writing "admin.conf" kubeconfig file
[kubeconfig] Writing "kubelet.conf" kubeconfig file
[kubeconfig] Writing "controller-manager.conf" kubeconfig file
[kubeconfig] Writing "scheduler.conf" kubeconfig file
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Starting the kubelet
[control-plane] Using manifest folder "/etc/kubernetes/manifests"
[control-plane] Creating static Pod manifest for "kube-apiserver"
[control-plane] Creating static Pod manifest for "kube-controller-manager"
[control-plane] Creating static Pod manifest for "kube-scheduler"
[etcd] Creating static Pod manifest for local etcd in "/etc/kubernetes/manifests"
[wait-control-plane] Waiting for the kubelet to boot up the control plane as static Pods from directory "/etc/kubernetes/manifests". This can take up to 4m0s
[apiclient] All control plane components are healthy after 19.503398 seconds
[upload-config] Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace
[kubelet] Creating a ConfigMap "kubelet-config-1.19" in namespace kube-system with the configuration for the kubelets in the cluster
[upload-certs] Skipping phase. Please see --upload-certs
[mark-control-plane] Marking the node k8smaster as control-plane by adding the label "node-role.kubernetes.io/master=''"
[mark-control-plane] Marking the node k8smaster as control-plane by adding the taints [node-role.kubernetes.io/master:NoSchedule]
[bootstrap-token] Using token: zp0v2c.iuh4850t3daaj1tn
[bootstrap-token] Configuring bootstrap tokens, cluster-info ConfigMap, RBAC Roles
[bootstrap-token] configured RBAC rules to allow Node Bootstrap tokens to get nodes
[bootstrap-token] configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials
[bootstrap-token] configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token
[bootstrap-token] configured RBAC rules to allow certificate rotation for all node client certificates in the cluster
[bootstrap-token] Creating the "cluster-info" ConfigMap in the "kube-public" namespace
[kubelet-finalize] Updating "/etc/kubernetes/kubelet.conf" to point to a rotatable kubelet client certificate and key
[addons] Applied essential addon: CoreDNS
[addons] Applied essential addon: kube-proxy
Your Kubernetes control-plane has initialized successfully!
To start using your cluster, you need to run the following as a regular user:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
https://kubernetes.io/docs/concepts/cluster-administration/addons/
Then you can join any number of worker nodes by running the following on each as root:
kubeadm join 192.168.65.133:6443 --token zp0v2c.iuh4850t3daaj1tn \
--discovery-token-ca-cert-hash sha256:c4d3486feabd40009801526da89b2d227e4a130f692ec034746648c0ceab626e
说明:
service-cidr 的选取不能和PodCIDR及本机网络有重叠或者冲突,一般可以选择一个本机网络和PodCIDR都没有用到的私网地址段,比如PODCIDR使用10.244.0.0/16, 那么service cidr可以选择10.96.0.0/12,网络无重叠冲突即可;
(5)在Master节点上执行
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
kubectl get nodes
(6)Node节点加入Kubernetes集群(在Node节点执行)
kubeadm join 192.168.65.133:6443 --token zp0v2c.iuh4850t3daaj1tn \
--discovery-token-ca-cert-hash sha256:c4d3486feabd40009801526da89b2d227e4a130f692ec034746648c0ceab626e
输出结果:
[preflight] Running pre-flight checks
[WARNING SystemVerification]: missing optional cgroups: pids
[preflight] Reading configuration from the cluster...
[preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -oyaml'
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Starting the kubelet
[kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap...
This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.
Run 'kubectl get nodes' on the control-plane to see this node join the cluster.
(7)查看Nodes(主节点)
kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8smaster NotReady master 5m56s v1.19.4
k8snode1 NotReady <none> 56s v1.19.4
k8snode2 NotReady <none> 5s v1.19.4
发现都是NotReady状态
3.4 部署网络插件
(1)下载kube-flannel.yml文件
wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
文件见 ./pkg/kube-flannel.yml
(2)应用kube-flannel.yml文件得到运行时容器(主节点)
kubectl apply -f kube-flannel.yml
输出结果:
podsecuritypolicy.policy/psp.flannel.unprivileged created
clusterrole.rbac.authorization.k8s.io/flannel created
clusterrolebinding.rbac.authorization.k8s.io/flannel created
serviceaccount/flannel created
configmap/kube-flannel-cfg created
daemonset.apps/kube-flannel-ds created
(3)重启(主节点)
(4)查看Nodes(主节点)
kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8smaster Ready master 39m v1.19.4
k8snode1 Ready <none> 34m v1.19.4
k8snode2 Ready <none> 33m v1.19.4
(5)查看Pod状态
kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-6d56c8448f-snghb 1/1 Running 0 39m
coredns-6d56c8448f-tjgsd 1/1 Running 0 39m
etcd-k8smaster 1/1 Running 1 33s
kube-apiserver-k8smaster 1/1 Running 1 58s
kube-controller-manager-k8smaster 1/1 Running 1 31s
kube-flannel-ds-czlv9 1/1 Running 0 26m
kube-flannel-ds-j4v7k 1/1 Running 0 26m
kube-flannel-ds-j9vhb 1/1 Running 0 26m
kube-proxy-cwn25 1/1 Running 0 34m
kube-proxy-w47mf 1/1 Running 0 34m
kube-proxy-x72bn 1/1 Running 0 39m
kube-scheduler-k8smaster 1/1 Running 1 54s
(6)查看Pod分布在哪个节点
kubectl get pods -n kube-system -o wide
三、Kubernetes常用命令
获取当前命名空间下的容器
kubectl get pods
获取所有容器列表
kubectl get all
创建容器
kubectl create -f kubernate-pvc.yaml
kubectl apply -f kubernate-pvc.yaml
此两条命令在第一次创建时没区别,但是apply可以多次执行创建,进行修补
创建deployment
kubectl create deployment 【deploy_name】 --image=镜像
暴露服务
kubectl expose deployment 【deploy_name】 --port=容器端口号 --type=NodePort
删除容器
kubectl delete pods/test-pd 或者 kubectl delete -f rc-nginx.yaml
查看指定pod在哪个node上运行
kubectl get pod/test-pd -o wide
查看容器日志
kubectl logs nginx-8586cf59-mwwtc
进入容器终端
kubectl exec -it nginx-8586cf59-mwwtc /bin/bash
一个Pod里含有多个容器,用--container or -c 参数
例如:有个pod名为my-pod,这个pod有两个容器,分别名为main-app和helper-app,下面的命令将打开到main-app的shell容器里
kubectl exec -it my-pod --container main-app -- /bin/bash
容器详情列表
kubectl describe pod/mysql-m8rbl
查看容器状态
kubectl get svc
空运行测试
kubectl create deployment 【deploy_name】 --image=镜像 --dry-run -o yaml
kubectl create deployment 【deploy_name】 --image=镜像 --dry-run -o json
可以打印出yaml或json内容
kubectl create deployment 【deploy_name】 --image=镜像 --dry-run -o yaml > deploy.yaml
kubectl create deployment 【deploy_name】 --image=镜像 --dry-run -o json > deploy.json
将打印的yaml或json内进行保存
四、Kubernetes核心组件
-
apiserver
API server是所有请求的唯一入口; api server管理所有的事务,并把信息记录到etcd数据库中,etcd有一个自动服务发现的特性机制,etcd会搭建有三个节点的集群,实现三副本;
-
scheduler
scheduler 调度器用来调度资源,查看业务节点的资源情况,确定在哪个node上创建pod,把指令告知给api server;
-
controller-manager
控制管理器controller-manager管理pod; pod可以分为有状态和无状态的pod,一个pod里最好只放一个容器;
总结:
api server把任务下发给业务节点的kubelet去执行;
客户访问通过kube-proxy去访问pod;
pod下面的不一定是docker,还有别的容器;
一般pod中只包含一个容器,除了一种情况除外,那就是elk,elk会在pod内多放一个logstash去收集日志;
1.Pod详解
Pod是Kubernetes的最重要概念,每个Pod都有一个特殊的被称为“根容器”的Pause容器。
Pause容器对应的镜像属于Kubernetes平台的一部分,除了Pause容器,每个Pod还包含一个或多个紧密相关的用于业务容器
-
Pod vs 应用
每个Pod都是应用的一个实例,有专用的IP
-
Pod vs 容器
一个Pod可以有多个容器,彼此间共享网络和存储资源,每个Pod中有一个Pause容器保存所有容器的状态,通过管理Pause容器,达到管理Pod中所有容器的效果
-
Pod vs 节点
同一个Pod中的容器总会被调度到相同Node节点,不同节点间的通信基于虚拟二层网络技术实现
-
Pod vs Pod
普通Pod和静态Pod
1.1.Pod的定义
下面是yaml文件定义的Pod的完整内容
apiVersion: v1 //版本
kind: Pod //类型,Pod
metadata: //元数据
name: string //元数据,Pod的名字
namespace: string //元数据,Pod的明明空间
labels: //元数据,标签列表
- name: string //元数据,标签的名字
annotations: //元数据,自定义注解列表
- name: string //元数据,自定义注解名字
spec: //Pod中容器的详细定义
containers: //Pod中的容器列表,可以有多个容器
- name: string //容器的名称
image: string //容器中的镜像
imagesPullPolicy: [Always|Never|IfNotPresent] //获取镜像的策略,默认值为Always,每次都尝试重新下载镜像
command: [string] //容器的启动命令列表(不配置的话使用镜像内部的命令)
args: [string] //启动参数列表
workingDir: string //容器的工作目录
volumeMounts: //挂在到容器内部的存储卷设置
- name: string
mountPath: string //存储卷在容器内部Mount的绝对路径
readOnly: boolean //默认值为读写
ports: //容器需要暴露的端口号列表
- name: string
containerPort: int //容器要暴露的端口
hostPort: int //容器所在主机监听的端口(容器暴露端口映射到宿主机的端口,设置hostPort时同一个宿主机将不能再启动该容器的第2份副本)
protocol: string //TCP和UDP,默认值为TCP
env: //容器运行前要设置的环境列表
- name: string
value: string
resources:
limits: //资源限制,容器的最大可用资源
cpu: string
memory: string
requeste: //资源限制,容器启动的初始可用资源数量
cpu: string
memory: string
livenessProbe: //Pod内容器健康检查的设置
exec:
command: [string] //exec方式需要指定的命令或脚本
httpGet: //通过httpget检查健康
path: string
port: number
host: string
scheme: string
httpHeaders:
- name: string
value: string
tcpSocket: //通过tcpSocket检查健康
port: number
initialDelaySeconds: 0 //首次检查时间
timeoutSeconds: 0 //检查超时时间
periodSeconds: 0 //检查间隔时间
successThreshold: 0
failureThreshold: 0
securityContext: //安全检查
privileged: false
restartPolicy: [Always|Never|OnFailure] //重启策略,默认值为Always
nodeSelector: object //节点选择,表示将该Pod调度到包含这些label的Node上,以key:value格式指定
imagePullSecrets:
- name: string
hostNetwork: false //是否使用主机网络模式,启用Docker网桥,默认否
volumes: //在该Pod上定义共享存储卷列表
- name: string
emptyDir: {} //是一种与Pod同生命周期的存储卷,是一个临时目录,内容为空
hostPath: string //Pod所在主机上的目录,将被用于容器中mount的目录
path: string
secret: //类型为secret的存储卷
secretName: string
item:
- key: string
path: string
configMap: //类型为configMap的存储卷
name: string
items:
- key: string
path: string
1.2.Pod的基本用法
在Kubernetes中对运行容器的要求为:容器的主程序需要一直在前台运行,而不是后台运行。
应用需要改造成前台运行的方式
如果我们创建的Docker镜像的启动命令是后台执行程序,则在kubelet创建包含这个容器的Pod之后运行完该命令,即认为Pod已经结束,将立刻销毁该Pod。
如果认为该Pod定义了RC,则创建、销毁会陷入一个无限循环的过程中
Pod可以由1个或多个容器组合而成
-
由一个容器组成的Pod示例
#一个容器组成的Pod apiVersion: v1 kind: Pod metadata: name: mytomcat labels: name: mytomcat spec: containers: - name: mytomcat image: tomcat ports: - containerPort: 8000
-
由两个为紧耦合的容器组成的Pod示例
#两个紧耦合的容器 apiVersion: v1 kind: Pod metadata: name: myweb labels: name: tomcat-redis spec: containers: - name: tomcat image: tomcat ports: - containerPort: 8080 - name: redis image: redis ports: - containerPort: 6379
-
创建
kubectl create -f xxx.yaml
-
查看
kubectl get pod/po <Pod_name> kubectl get pod/po <Pod_name> -o wide kubectl describe pod/po <Pod_name>
-
删除
kubectl delete -f pod xxx.yaml kubectl delete pod --all/[pod_name]
1.3.Pod的分类
Pod有两种类型
-
普通Pod
普通Pod一旦被创建,就会被放入到etcd中存储,随后会被Kubernetes Master调度到某个具体的Node上并进行绑定,随后该Pod对应的Node上的kubelet进程实例化成一组相关的Docker容器并启动起来
在默认情况下,当Pod里某个容器停止时,Kubernetes会自动检测到这个问题并且重新启动这个Pod里某所有容器,如果Pod所在的Node宕机,则会将这个Node上的所有Pod重新调度到其他节点上
-
静态Pod
静态Pod是有kubelet进行管理的仅存在于特定Node上的Pod,他们不能通过API Server进行管理,无法与ReplicationController、Deployment或DaemonSet进行关联,并且kubelet也无法对它们进行健康检查
1.4.Pod生命周期和重启策略
-
Pod的状态
状态值 说明 Pending API Server已经创建了该Pod,但Pod中的一个或多个容器的镜像还没有创建,包括镜像下载过程 Running Pod内所有容器已创建,且至少一个容器处于运行状态、正在启动状态或正在重启状态 Completed Pod内所有容器均成功执行突出,且不会再重启 Failed Pod内所有容器均已退出,但至少一个容器退出失败 Unknown 由于某种原因无法获取Pod状态,例如网络通信不畅 -
Pod重启策略
Pod的重启策略包括Always、OnFailure和Never,默认值是Always
重启策略 说明 Always 当容器失效时,由kubelet自动重启该容器 OnFailure 当容器终止运行且退出码不为0时,有kubelet自动重启该容器 Never 不论容器运行状态如何,kubelet都不会重启该容器 -
常见状态转换
Pod包含的容器数 Pod当前的状态 发生事件 Pod的结果状态 RestartPolicy=Always RestartPolicy=OnFailure RestartPolicy=Never 包含一个容器 Running 容器成功退出 Running Succeeded Succeeded 包含一个容器 Running 容器失败退出 Running Running Failure 包含两个容器 Running 1个容器失败退出 Running Running Running 包含两个容器 Running 容器被OOM杀掉 Running Running Failure
1.5.Pod资源配置
每个Pod都可以对其能使用的服务器上的计算资源设置限额,kubernetes中可以设置限额的计算资源有CPU与Memory两种,其中CPU的资源单位为CPU数量,是一个绝对值而非相对值。
Memory配置也是一个绝对值,他的单位是内存字节数
kubernetes里,一个计算资源进行配额限定需要设定一下两个参数
Requests:该资源最小申请数量,系统必须满足要求
Limits:该资源最大允许使用的量,不能突破吗,当容器试图使用超过这个量的资源时,可能会被kubernetes kill并重启
spec:
containers:
- name: db
image: mysql
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
上述代码表明MYSQL容器申请最少0.25个CPU以及64MiB内存,在运行过程中容器所能使用的资源配额为0.5个CPU以及128MiB内存
2.Label详解
Label是kubernetes系统中另一个核心概念。
一个Label是一个key value的键值对,其中key与value由用户自己指定
label可以附加到各种资源对象上,如Node、Pod、Service、RC,一个资源对象可以定义任意数量的Label
同一个Label也可以被添加到任意数量的资源对象上,Label通常在资源对象定义时确定,也可以在对象创建后动态的添加或删除
Label的最常见的用法是使用metadata.labels字段,来为对象添加label,通过spec.selector来引用对象
apiVersion: v1
kind: ReplicationController
metadata:
name: nginx
spec:
replicas: 3
selector:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
----------------------------------------
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
type: NodePort
ports:
- port: 80
nodePort: 33333
selector:
app: nginx
Label附加到kubernetes集群中的各种资源对象上,目的就是对这些资源对象进行分组管理,而分组管理的核心就是Label Selector
Label与Label Selector都是不能单独定义,必须附加在一些资源对象的定义文件上,一般附加在RC和Service的资源定义文件中
3.Replication Controller详解
Replication Controller(RC)是kubernetes系统中核心概念之一
当我们定义了一个RC并提交到kubernetes集群中以后,Master节点上的Controller Manager组件就得到通知,定期检查系统中存活的Pod,并确保目标Pod实例的数量刚好等于RC的预期值,如果有过多或过少的Pod运行,系统就会停掉或创建一些Pod,此外我们也可以通过修改RC的副本数量,来实现Pod的动态缩放功能
kubectl scale rc nginx --replicas=5
由于Replication Controller与kubernetes代码中的模块Replication Controller同名,所以在kubernetes v1.2时,它就升级成了另外一个新的概念Replica Sets,官方解释为下一代的RC,它与RC区别是:Replica Sets支援基于集合的Label Selector,而RC只支持基于等式的Label Selector。
我们很少单独使用Replica Sets,它主要被Deployment这个更高层面的资源对象所使用,从而形成一整套Pod的创建、删除、更新的编排机制
最好不要越过RC直接创建Pod,因为Replication Controller会通过RC管理Pod副本,实现自动创建、补足、替换、删除Pod副本,这样就能够提高应用的容灾能力,减少由于节点崩溃等意外状况造成的损失。
即使应用程序只有一个Pod副本,也强烈建议使用RC来定义Pod
4.Replica Set详解
ReplicaSet跟Replication Controller没有本质的不同,只是名字不一样,并且RepicaSet支持集合式的selector(RepicationController仅支持等式)
kubernetes官方强烈建议避免直接使用ReplicaSet,而应该通过Deployment来创建RS和Pod
由于ReplicaSet是ReplicationController的替代,因此用法基本相同,唯一的区别在于ReplicaSet支持集合式的selector
5.Deployment详解
Deploynent是kubernetes v1.2引入的新概念,引入的目的是为了更好的解决Pod的编排问题,Deployment内部使用了ReplicaSet来实现
Deployment的定义与ReplicaSet的定义很类似,除了API声明与Kind类型有所区别
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: frontend
spec:
replicas: 1
selector:
matchLabels:
tier: frontend
matchExpressions:
- {key: tier,operator: In,values: [frontend]}
template:
metadata:
labels:
app: app-demo
tier: frontend
spec:
containers:
- name: tomcat-demo
image: tomcat
ports:
-containerPort: 8080
6.Horizontal Pod Autoscaler
Horizontal Pod Autoscaler(Pod横向扩容 简称HPA)与RC、Deployment一样,也属于一种kubernetes资源对象。
通过跟踪分析RC控制的所有目标Pod的负载变化情况,来确定是否需要针对性的调整目标Pod的副本数,这是HPA的实现原理
kubernetes对Pod扩容与缩容提供了手动和自动两种模式,手动模式通过kubelet scale命令对一个Deployment/RC进行Pod副本数量的设置。自动模式则需要用户根据某个性能指标或者自定义定业务指标,并制定Pod副本数量的范围,系统将自动在这个范围内根据性能指标的变化进行调整
-
手动扩容和缩容
kubectl scale deployment frontend --replicas 1
-
自动扩容和缩容
HPA控制器基本Master的kube-controller-manager服务启动参数–horizontal-pod-autoscaler-sync-period定义的时长(默认值为30s),周期性的检测Pod的CPU使用率,并在满足条件时对RC或Deployment中的Pod副本数量进行调整,以符合用户定义的平局Pod CPU使用率
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: nginx-deployment spec: replicas: 1 template: metadata: name: nginx labels: app: nginx spec: containers: - name: nginx image: nginx resources: requests: cpu: 50m ports: containerPort: 80 -------------------------------------- apiVersion: v1 kind: Service metadata: name: nginx-svc spec: ports: - port: 80 selector: app: nginx -------------------------------------- apiVersion: autoscaling/v1 kind: HorizontalPodAutoscaler metadata: name: nginx-hpa spec: scaleTargetRef: apiVersion: app/v1beta1 kind: Deployment name: nginx-deployment minReplicas: 1 maxReplicas: 10 targetCPUUtilizationPercentage: 50
7.Volume详解
Volume是Pod中能够被多个容器访问的共享目录
Kubernetes的Volume定义在Pod上,它被一个Pod中的多个容器挂在到具体的文件目录下
Volume与Pod的生命周期相同,但与容器的生命周期不相关,当容器终止或重启时,Volume中的数据也不会丢失。
要使用Volume,pod需要制定volume的类型和内容(spec.volumes字段),和映射到容器的位置(spec.container.volumeMounts字段)
kubernetes支持多种类型的Volume,包括:emptyDir、hostPath、gcePersistentDish、awsElasticBlockStore、nfs、iscsi、flocker、glusterfs、rbd、cephfs、gitRepo、secret、persistentVolumeClain、downwardAPI、azureFileVolume、azureDisk、vsphereVolume、Quobyte、PortworxVolume、ScaleIO
-
emptyDir
EmptyDir类型的Volume创建于Pod被调度到某个宿主机上的时候,而同一个pod内的容器都能读写EmptyDir中的同一个文件。一旦这个Pod离开了这个宿主机,EmptyDir中的数据就会被永久删除。所以目前EmptyDir类型的volume主要用作临时空间,比如Web服务器写日志或者tmp文件需要的临时目录。
yaml示例如下
apiVersion: v1 kind: Pod metadata: name: test-pd spec: containers: - iamge: docker.io/nazarpc/webserver name: test-container volumeMounts: - mountPath: /cache name: cache-volume volumes: - name: cache-volume emptyDir: {}
-
hostPath
HostPath属性的volume使得对应的容器能够访问当前宿主机上的指定目录。例如,需要运行一个访问Docker系统目录的容器,那么久使用/var/lib/docker目录作为一个HostDir类型的volume;或者要在一个容器内部运行CAdvisor,那么久使用/dev/cgroups目录作为一个HostDir类型的volume
一旦这个Pod离开了这个宿主机,HostDir中的数据虽然不会被永久删除,但数据也不会随pod迁移到其他宿主机上
因此,需要注意的是,由于各个宿主机上的文件系统结构和内容并不一定完全相同,所以相同pod的HostDir可能会在不同的宿主机上表现出不同的行为
yaml示例如下
apiVersion: v1 kind: Pod metadata: name: test-pd spec: containers: - image: docker.lio/nazarpc/webserver name: test-container #指定在容器中挂载路径 volumeMounts: - mountPath: /test-pd name: test-volume #指定所提供的存储卷 volumes: - name: test-volume #宿主机上的目录 hostPath: # directory location on host path: /data
-
nfs
NFS类型的volume。允许一块现有的网络硬盘在同一个pod内的容器间共享
yaml示例如下
apiVersion: apps/v1 kind: Deployment metadata: name: redis spec: selector: matchLabels: app: redis revisionHistoryLimit: 2 template: metadata: labels: app: redis spec: containers: #应用镜像 - image: redis name: redis imagePullPolicy: IfNotPresent #应用的内部端口 ports: - containerPort: 6379 name: redis6379 env: - name: ALLOW_EMPTY_PASSWORD value: "yes" - name: REDIS_PASSWORD value: "redis" #持久化挂载位置,在docker中 volumeMounts: #宿主机上的目录 - name: redis-persistent-storage nfs: path: /k8s-nfs/redis/data server: 192.168.126.112
8.Namespace详解
Namespace在很多情况下用于实现多用户的资源隔离,通过将集群内部的资源对象分配到不同的Namespace中,形成逻辑上的分组,便于不同的分组在共享使用整个集群的资源同时还能被分别管理
kubernetes集群在启动后,会形成一个名为“default"的Namespace,如果不特别指定Namespace,则用户创建的Pod,RC,Service都将被系统创建到这个默认的名为default的Namespace中
-
Namespace创建
apiVersion: v1 kind: Namespace metadata: name:development ----------------- apiVersion: v1 kind: Pod metadata: name: busybox namespace:development spec: containers: - image: busybox command: - sleep - "3600" name: busybox
-
Namespace查看
kubectl get pods --namespace=development
9.Service详解
Service是kubernetes最核心的概念,通过创建service,可以为一组具有相同功能的容器应用提供一个统一的入口地址,并且将请求负载分发到后端的各个容器应用上
9.1.Service的定义
yaml格式的Service定义文件
apiVersion: v1
kind: Service
metadata:
name: string
namespace: string
labels:
- name: string
annotations:
- name: string
spec:
selector: []
type: string
clusterIP: string
sessionAffinity: string
ports:
- name: string
protocol: string
port: int
targetPort: int
nodePort: int
status:
loadBalance:
ingress:
ip: string
hostname: string
属性名称 | 取值类型 | 是否必选 | 取值说明 |
---|---|---|---|
version | string | Required | v1 |
kind | string | Required | Service |
metadata | object | Required | 元数据 |
metadata.name | string | Required | Service名称 |
metadata.namespace | string | Required | 命名空间,默认为default |
metadata.labels[] | list | 自定义标签属性列表 | |
metadata.annotation[] | list | 自定义注解属性列表 | |
spec | object | Rquired | 详细描述 |
spec.selector[] | list | Required | Label Selector配置,将选择具有指定Label标签的Pod作为管理范围 |
spec.type | string | Required | Service的类型,指定Service的访问方式,默认值为ClusterIP。取值范围如下:ClusterIP,虚拟服务的IP,用于k8s集群内部的pod访问,在Node上kube-proxy通过设置的iptables规则进行转发;NodePort,使用宿主机的端口,使用能够访问个Node外部客户端通过Node的IP地址和端口就能访问服务;LoadBalancer,使用外接负载均衡器完成到服务的负载分发,需要在spec.status.loadBalancer字段指定为爱步负载均衡器的ip地址,并同时定义nodePort和clusterIP,用于公有云环境 |
spec.clusterIP | string | 虚拟服务的IP地址,当type=clusterIP时,如果不指定,则系统进行自动分配,也可以手动指定。当type=LoadBalancer时,则需要指定 | |
spec.sessionAffinity | string | 是否支撑session,可选择为ClientIP,表示将同一个源IP地址的客户端访问请求都转发到同一个后端Pod,默认为空 | |
spec.ports[] | list | Service需要暴露的端口列表 | |
spec.ports[].name | string | 端口名称 | |
spec.ports[].protocol | string | 端口协议,支持TCP和UDP,默认值为TCP | |
spec.ports[].port | int | 服务监听的端口号 | |
spec.ports[].targetPort | int | 需要转发到后端Pod的端口号 | |
spec.ports[].nodePort | int | 当spec.type=NodePort时,指定映射到物理机的端口号 | |
status | object | 当spec.type=LoadBalancer时,设置外部负载均衡器的地址,用于公有云环境 | |
status.loadBalancer | object | 外部负载均衡器 | |
status.loadBalancer.ingress | object | 外部负载均衡器 | |
statsu.loadBalancer.ingress.ip | string | 外部负载均衡器的IP地址 | |
status.loadBalancer.ingress.hostname | string | 外部负载均衡器的主机名 |
9.2.Service的基本用法
一般来说,对外提供服务的应用程序需要通过某种机制来实现,对于容器应用最简便的方式就是通过TCP/IP机制及监听IP和端口号来实现
创建一个基本功能的service
apiVersion: v1
kind: ReplicationController
metadata:
name: mywebapp
spec:
replicas: 2
template:
metadata:
name: mywebapp
labels:
app: mywebapp
spec:
containers:
- name: mywebapp
image: tomcat
ports:
- containerPort: 8080
我们可以通过kubectl get pods -l app=mywebapp -o yaml | grep podIP来获取Pod的IP地址和端口号来访问Tomcat服务,但是直接通过Pod的ip地址和端口号访问应用服务是不可靠的,因为当Pod所在的Node发生故障时,Pod将被kubernetes重新调度到另一台Node,Pod的地址会发生该表。
我们可以通过配置文件来定义Service,再通过kubectl create 来创建,这样可以通过Service地址来访问后端的Pod
apiVersion: v1
kind: Service
metadata:
name: mywebAppService
spec:
ports:
- port: 8081
targetPort: 8080
selector:
app: mywebapp
9.2.1.多端口Service
有时一个容器也可能提供多个端口的服务,那么在Service的定义中也可以相应的设置为将多个端口对应到多个应用服务
apiVersion: v1
kind: Service
metadata:
name: mywebAppService
spec:
ports:
- port: 8080
targetPort: 8080
- port: 8005
targetPort: 8005
name: management
selector:
app: mywebapp
9.2.2.外部服务Service
在某些特殊环境中吗,应用系统需要将一个外部数据库作为后端服务进行连接,或将另一个集群或Namespace中的服务作为服务的后端,这是可以通过创建一个无Label Selector的Service来实现
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
ports:
- protocol: TCP
port: 80
tartgetPort: 80
--------------------
apiVersion: v1
kind: EndPoints
metadata:
name: my-service
subsets:
- address:
- IP: 10.254.74.13
ports:
- port: 8080
五、Kubernetes部署容器化应用
Docker应用–>在docker里面部署一个java程序(springboot)
5.1 部署nginx
kubectl create deployment nginx --image=nginx
kubectl expose deployment nginx --port=80 --type=NodePort
kubectl get pod,svc
NAME READY STATUS RESTARTS AGE
pod/nginx-6799fc88d8-4jw88 1/1 Running 0 2m54s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 53m
service/nginx NodePort 10.100.253.65 <none> 80:30948/TCP 6s
http://192.168.65.133:30948/
5.2 部署Tomcat
kubectl create deployment tomcat --image=tomcat
kubectl expose deployment tomcat --port=8080 --type=NodePort
5.3 部署微服务(springboot程序)
1、项目打包(jar、war)-->可以采用一些工具git、maven、jenkins
2、制作Dockerfile文件,生成镜像;
3、kubectl create deployment nginx --image= 你的镜像
4、你的springboot就部署好了,是以docker容器的方式运行在pod里面的;
(1)自定义JDK镜像(Node节点,可以三个节点都执行下,或者save后load)
vi /opt/Dockerfile
FROM centos:latest
MAINTAINER zhuyan
ADD jdk-8u171-linux-x64.tar.gz /usr/local/java
ENV JAVA_HOME /usr/local/java/jdk1.8.0_171
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV PATH $PATH:$JAVA_HOME/bin
CMD java -version
构建镜像:docker build -t jdk1.8.0_171 .
运行镜像:docker run -di 镜像id(或者镜像名称)
(2)构建springboot项目镜像(Node节点,可以三个节点都执行下,或者save后load)
mkdir -p /opt/springboot
vi /opt/springboot/Dockerfile
FROM jdk1.8.0_171
MAINTAINER zhuyan
ADD 38-springboot-k8s-1.0.0.jar /opt
RUN chmod +x /opt/38-springboot-k8s-1.0.0.jar
CMD java -jar /opt/38-springboot-k8s-1.0.0.jar
构建镜像:docker build -t 38-springboot-k8s-1.0.0-jar .
(3)空运行测试(主节点)
--方式1:打印yaml
kubectl create deployment springboot-k8s --image=38-springboot-k8s-1.0.0-jar --dry-run -o yaml
--方式2:打印json
kubectl create deployment springboot-k8s --image=38-springboot-k8s-1.0.0-jar --dry-run -o json
--方式3:打印yaml,并保存到 deploy.yaml
kubectl create deployment springboot-k8s --image=38-springboot-k8s-1.0.0-jar --dry-run -o yaml > deploy.yaml
--方式4:打印json,并保存到 deploy.json
kubectl create deployment springboot-k8s --image=38-springboot-k8s-1.0.0-jar --dry-run -o json> deploy.json
(4)修改deploy.yaml文件(主节点)
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: springboot-k8s
name: springboot-k8s
spec:
replicas: 1
selector:
matchLabels:
app: springboot-k8s
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: springboot-k8s
spec:
containers:
- image: 38-springboot-k8s-1.0.0-jar
imagePullPolicy: Never
name: 38-springboot-k8s-1-0-0-jar-2678v
resources: {}
status: {}
增加 imagePullPolicy: Never, 把镜像拉取策略改为Never;
(5)yaml文件部署(主节点)
kubectl apply -f deploy.yaml
等价于:
kubectl create deployment springboot-k8s --image=38-springboot-k8s-1.0.0-jar (省略(3)、(4)步骤)
(6)查看信息
--查看pod详细信息
kubectl describe pods springboot-k8s-699cbb7f7-58hkz(pod名称)
--检查是否创建了deployments任务
kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
nginx 1/1 1 1 14h
springboot-k8s 1/1 1 1 8m14s
tomcat 1/1 1 1 14h
--查看pod日志
kubectl logs springboot-k8s-699cbb7f7-58hkz(pod名称)
(7)暴露服务空执行
--方式1:打印yaml
kubectl expose deployment springboot-k8s --port=8080 --type=NodePort --dry-run -o yaml
--方式2:打印json
kubectl expose deployment springboot-k8s --port=8080 --type=NodePort --dry-run -o json
--方式3:打印yaml,并保存到 deploy-service.yaml
kubectl expose deployment springboot-k8s --port=8080 --type=NodePort --dry-run -o yaml > deploy-service.yaml
--方式4:打印json,并保存到 deploy-service.json
kubectl expose deployment springboot-k8s --port=8080 --type=NodePort --dry-run -o json> deploy-service.json
(8)查看deploy-service.yaml
vi deploy-service.yaml
apiVersion: v1
kind: Service
metadata:
creationTimestamp: null
labels:
app: springboot-k8s
name: springboot-k8s
spec:
ports:
- port: 8080
protocol: TCP
targetPort: 8080
selector:
app: springboot-k8s
type: NodePort
status:
loadBalancer: {}
(9)执行暴露服务
kubectl create -f deploy-service.yaml
或
kubectl apply -f deploy-service.yaml
等价于:
kubectl expose deployment springboot-k8s --port=8080 --type=NodePort (省略(7)、(8)步骤)
(10)查看信息
--查看服务
kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 15h
nginx NodePort 10.100.253.65 <none> 80:30948/TCP 14h
springboot-k8s NodePort 10.103.30.92 <none> 8080:30673/TCP 5m46s
tomcat NodePort 10.108.134.142 <none> 8080:30455/TCP 14h
(11)访问
http://192.168.65.136:30673/38-springboot-k8s/json
5.4 部署Kubernetes Dashbaord
Kubernetes仪表盘是Kubernetes集群的基于Web的通用UI,它允许用户管理群集中运行的应用程序并对其进行故障排除,以及管理群集本身;
Github:https://github.com/kubernetes/dashboard
(1)下载yaml的资源清单
wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.4/aio/deploy/recommended.yaml
见 ./pkg/recommended.yaml
(2)应用yaml的资源清单
kubectl apply -f recommended.yaml
namespace/kubernetes-dashboard created
serviceaccount/kubernetes-dashboard created
service/kubernetes-dashboard created
secret/kubernetes-dashboard-certs created
secret/kubernetes-dashboard-csrf created
secret/kubernetes-dashboard-key-holder created
configmap/kubernetes-dashboard-settings created
role.rbac.authorization.k8s.io/kubernetes-dashboard created
clusterrole.rbac.authorization.k8s.io/kubernetes-dashboard created
rolebinding.rbac.authorization.k8s.io/kubernetes-dashboard created
clusterrolebinding.rbac.authorization.k8s.io/kubernetes-dashboard created
deployment.apps/kubernetes-dashboard created
service/dashboard-metrics-scraper created
deployment.apps/dashboard-metrics-scraper created
(3)查看pod是否成功
注意命名空间是在 kubernetes-dashboard 下面
kubectl get pod -n kubernetes-dashboard
NAME READY STATUS RESTARTS AGE
dashboard-metrics-scraper-7b59f7d4df-vkf8z 1/1 Running 0 62s
kubernetes-dashboard-665f4c5ff-rm86x 1/1 Running 0 62s
(3)访问
https://192.168.65.136:30001/
需要输入token,token的生成采用以下三条命令
kubectl create serviceaccount dashboard-admin -n kube-system
kubectl create clusterrolebinding dashboard-admin --clusterrole=cluster-admin --serviceaccount=kube-system:dashboard-admin
kubectl describe secrets -n kube-system $(kubectl -n kube-system get secret | awk '/dashboard-admin/{print $1}')
5.5 Ingress暴露应用
5.5.1 NodePort问题
NodePort服务是让外部请求直接访问服务的最原始方式
NodePort是在所有的节点(虚拟机)上开放指定的端口,所有发送到这个端口的请求都会直接转发到服务中的pod里
NodePort服务的yaml文件格式如下:
apiVersion: v1
kind: Service
metadata:
name: my-nodeport-service
selector:
app: my-appspec:
type: NodePort
ports:
- name: http
port: 80
targetPort: 80
nodePort: 30008
protocol: TCP
这种方式有一个“NodePort”的端口,能在节点上指定开放哪个端口,如果没有指定端口,它会选择一个随机端口,大多数时候应该让kubernetes随机选择端口
但是这种方式有很大的不足:
1.一个端口只能提供一个服务使用
2.只能使用30000-32767之间的端口
3.如果节点/虚拟机的ip地址发生变化,需要人工进行处理
因此在生产环境下不推荐这种方式来直接发布服务,如果不要求运行的服务实时可用或者用于演示或者临时运行一个应用可以采用这种方式
5.5.2 服务类型
Service的类型,指定Service的访问方式,默认值为ClusterIP。
取值范围如下:
-
ClusterIP,虚拟服务的IP,用于k8s集群内部的pod访问,在Node上kube-proxy通过设置的iptables规则进行转发;
-
NodePort,使用宿主机的端口,使用能够访问个Node外部客户端通过Node的IP地址和端口就能访问服务;
-
LoadBalancer,使用外接负载均衡器完成到服务的负载分发,需要在spec.status.loadBalancer字段指定为异步负载均衡器的ip地址,并同时定义nodePort和clusterIP,用于公有云环境
5.5.3 三种端口说明
ports:
- name: http
port: 80
targetPort: 80
nodePort: 30008
protocol: TCP
-
nodePort
外部机器(在windows浏览器)可以访问的端口; 比如一个Web应用需要被其他用户访问,那么需要配置type=NodePort,而且配置nodePort=30001,那么其他机器就可以通过浏览器访问scheme://node:30001访问到该服务;
-
targetPort
容器的端口,与制作容器时暴露的端口一致(Dockerfile中EXPOSE),例如docker.io官方的nginx暴露的是80端口;
-
port
Kubernetes集群中的各个服务之间访问的端口,虽然mysql容器暴露了3306端口,但外部机器不能访问到mysql服务,因为他没有配置NodePort类型,该3306端口是集群内其他容器需要通过3306端口访问该服务; kubectl expose deployment springboot-k8s --port=8080 --target-port=8080 --type=NodePort
5.5.4 Ingress
外部请求进入k8s集群的必经入口
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1hGquP57-1617614743960)(.\img\9.png)]
虽然k8s集群内部署的pod、service都有自己的ip,但是却无法提供外网访问,通过监听NodePort方式不了服务,这种方式并不灵活,生产环境也不建议使用
Ingress是k8s集群中的一个API资源对象,相当于一个集群网管,可以自定义路由规则来转发、管理、暴露服务(一组pod),比较灵活,生产环境建议使用此种方式
Ingress不是k8s内置的(安装好k8s之后,并没有安装ingress)
ingress需要单独安装,而且有多种类型Google Cloud Load Balancer、nginx、contour、istio等等
5.5.4.1 部署Ingress Nginx
(1)部署一个nginx容器化应用(为了掩饰将nginx服务的端口暴露出去)
kubectl create deployment nginx --image=nginx
(2)暴露该服务(为了掩饰将nginx服务的端口暴露出去)
kubectl expose deployment nginx --port=80 --target-port=80 --type=NodePort
(3)部署Ingress Nginx
https://github.com/kubernetes/ingress-nginx
ingress-nginx是使用NGINX作为反向代理和负载均衡器的Kubernetes的Ingress控制器;
https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v0.44.0/deploy/static/provider/baremetal/deploy.yaml
deploy.yaml见 ./pkg/deploy.yaml
332行修改成阿里云镜像:
阿里云镜像首页:http://dev.aliyun.com/
修改镜像地址为:
registry.cn-hangzhou.aliyuncs.com/google_containers/nginx-ingress-controller:0.33.0
如下图
spec:
hostNetwork: true
dnsPolicy: ClusterFirst
containers:
- name: controller
image: registry.cn-hangzhou.aliyuncs.com/google_containers/nginx-ingress-controller:0.33.0
imagePullPolicy: IfNotPresent
lifecycle:
preStop:
exec:
command:
- /wait-shutdown
部署
kubectl apply -f deploy.yaml
namespace/ingress-nginx created
serviceaccount/ingress-nginx created
configmap/ingress-nginx-controller created
clusterrole.rbac.authorization.k8s.io/ingress-nginx created
clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx created
role.rbac.authorization.k8s.io/ingress-nginx created
rolebinding.rbac.authorization.k8s.io/ingress-nginx created
service/ingress-nginx-controller-admission created
service/ingress-nginx-controller created
deployment.apps/ingress-nginx-controller created
validatingwebhookconfiguration.admissionregistration.k8s.io/ingress-nginx-admission created
serviceaccount/ingress-nginx-admission created
clusterrole.rbac.authorization.k8s.io/ingress-nginx-admission created
clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created
role.rbac.authorization.k8s.io/ingress-nginx-admission created
rolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created
job.batch/ingress-nginx-admission-create created
job.batch/ingress-nginx-admission-patch created
(4)查看Ingress状态
kubectl get service -n ingress-nginx
kubectl get deploy -n ingress-nginx
kubectl get pods -n ingress-nginx
5.5.4.2 配置Ingress Nginx规则
ingress-nginx-rule.yaml 见 ./pkg/ingress-nginx-rule.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: k8s-ingress
spec:
rules:
- host: www.abc.com
http:
paths:
- pathType: Prefix
path: /
backend:
service:
name: nginx #此处对应的是服务,如果想暴露tomcat,改成tomcat的服务即可,相应的要改下面的服务端口
port:
number: 80
kubectl apply -f ingress-nginx-rule.yaml
报错问题解决
kubectl delete -A ValidatingWebhookConfiguration ingress-nginx-admission
然后再次执行:kubectl apply -f ingress-nginx-rule.yaml
检查
kubectl get ing(ress)
5.6 部署SpringCloud微服务
1、项目本身打成jar包或者war包;
2、制作项目镜像(写Dockerfile文件);
3、用k8s部署镜像(命令方式、yaml方式);
4、对外暴露服务;
(1)微服务包
见 ./pkg/microservice 路径下
(2)制作Dockerfile(Node节点上)
vi Dockerfile-consumer
FROM jdk1.8.0_171
MAINTAINER zhuyan
ADD 0923-spring-cloud-alibaba-consumer-1.0.0.jar /opt
RUN chmod +x /opt/0923-spring-cloud-alibaba-consumer-1.0.0.jar
CMD java -jar /opt/0923-spring-cloud-alibaba-consumer-1.0.0.jar
vi Dockerfile-provider
FROM jdk1.8.0_171
MAINTAINER zhuyan
ADD 0923-spring-cloud-alibaba-provider-1.0.0.jar /opt
RUN chmod +x /opt/0923-spring-cloud-alibaba-provider-1.0.0.jar
CMD java -jar /opt/0923-spring-cloud-alibaba-provider-1.0.0.jar
vi Dockerfile-gateway
FROM jdk1.8.0_171
MAINTAINER zhuyan
ADD 0923-spring-cloud-alibaba-gateway-1.0.0.jar /opt
RUN chmod +x /opt/0923-spring-cloud-alibaba-gateway-1.0.0.jar
CMD java -jar /opt/0923-spring-cloud-alibaba-gateway-1.0.0.jar
(3)制作镜像(Node节点上)
docker build -t spring-cloud-alibaba-consumer -f Dockerfile-consumer .
docker build -t spring-cloud-alibaba-provider -f Dockerfile-provider .
docker build -t spring-cloud-alibaba-gateway -f Dockerfile-gateway .
(4)部署provider
kubectl create deployment spring-cloud-alibaba-provider --image=spring-cloud-alibaba-provider --dry-run -o yaml > provider.yaml
修改yaml文件,把镜像策略改成Never,从本地拉取
containers:
- image: spring-cloud-alibaba-provider
name: 0923-spring-cloud-alibaba-provider-1.0.0.jar-8ntrx
imagePullPolicy: Never #修改镜像拉取策略
kubectl apply -f provider.yaml
kubectl get pod
(5)部署consumer
kubectl create deployment spring-cloud-alibaba-consumer --image=spring-cloud-alibaba-consumer --dry-run -o yaml > consumer.yaml
修改yaml文件,把镜像策略改成Never,从本地拉取
containers:
- image: spring-cloud-alibaba-consumer
name: 0923-spring-cloud-alibaba-consumer-8ntrx
imagePullPolicy: Never #修改镜像拉取策略
kubectl apply -f consumer.yaml
kubectl expose deployment spring-cloud-alibaba-consumer --port=9090 --target-port=9090 --type=NodePort (此步可省略,因为可以使用gateway进行暴露)
kubectl get pod
(5)部署gateway
kubectl create deployment spring-cloud-alibaba-gateway --image=spring-cloud-alibaba-gateway --dry-run -o yaml > gateway.yaml
修改yaml文件,把镜像策略改成Never,从本地拉取
containers:
- image: spring-cloud-alibaba-gateway
name: 0923-spring-cloud-alibaba-gateway-8ntrx
imagePullPolicy: Never #修改镜像拉取策略
kubectl apply -f gateway.yaml
kubectl expose deployment spring-cloud-alibaba-gateway --port=80 --target-port=80 --type=NodePort
kubectl get pod
kubectl get svc 查看服务端口
(6)访问
通过上面得到的服务端口,如为 35610 ,则: http://192.168.65.133:35610/echo
(7)Ingress统一入口
查看ingress
kubectl get pods -n ingress-nginx
vi ingress-nginx-gateway-rule.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: k8s-ingress-cloud
spec:
rules:
- host: www.cloud.com
http:
paths:
- pathType: Prefix
path: /
backend:
service:
name: spring-cloud-alibaba-gateway
port:
number: 80
应用规则
kubectl apply -f ingress-nginx-gateway-rule.yaml
kubectl get ing 获取规则绑定的IP,如192.168.65.136
(8)采用ingress入口访问
在外部机器上配置hosts
规则绑定的ip www.cloud.com 如下
192.168.65.136 www.cloud.com
访问:http://www.cloud.com/echo