基础概念
公有云、私有云概念、混合云
云平台实战
开通阿里云ECS(按量计费)
配置访问工具
electermhttps://electerm.github.io/electerm/
https://wwa.lanzoui.com/b016k9bha 密码:900h
安装Nginx
# 安装
yum install nginx
# 启动
systemctl start nginx
安装完成以后验证,浏览器输入实例的公网IP地址
实例安全组配置
如图,实例在设置安全组以后,可以按需配置安全组相关设置。
私有网络VPC实战
VPC:私有网络、专有网络
云服务器集群各机器之间,一般使用私有IP访问。私有IP不占用公网IP流量,不同VPC网络下服务器之间互相隔离。同一VPC网络下,服务器互相连通。
如图所示,两个挂载在同一专用网络下的服务器,可以使用私有IP互相ping通
容器化基础
Docker基础
虚拟化技术
容器化技术
Docker基本概念
解决的问题
- 统一标准
应用构建:不同软件的打包、编译、安装、docker build
应用分享:docker hub
应用运行:统一标准的镜像、docker run
… - 资源的隔离
CPU、内存资源的隔离与限制
访问设备的隔离与限制
网络隔离与限制
用户、用户组隔离与限制
…
架构
- Docker Host:安装Docker的主机
- Docker Daemon:运行在Docker主机上的后台Docker进程
- Client:操作Docker主机的客户端:命令行/UI等
- Registry:镜像仓库、Docker Hub
- Images:镜像,带环境打包好的程序,可以直接运行
- Containers:由镜像启动起来的正在运行的程序
Docker实战
安装
- 移除之前的docker相关包(如有)
sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
- 配置yum源
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo \
http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
- 安装Docker
sudo yum install -y docker-ce docker-ce-cli containerd.io
#以下是在安装k8s的时候使用
yum install -y docker-ce-20.10.7 docker-ce-cli-20.10.7 containerd.io-1.4.6
- 启动
systemctl enable docker --now
- 配置加速器
阿里云提供了免费的镜像加速器
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://82m9ar63.mirror.aliyuncs.com"],
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
},
"storage-driver": "overlay2"
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
- 检查docker运行状态
docker ps
如果正确安装,控制台会输出如下内容。
实战
基础实战
- 镜像下载:docker hub 以Nginx为例:
# 下载最新版
docker pull nginx
# 下载指定版本
docker pull nginx:1.20.1
# 查看已经下载的镜像
docker images
# 移除镜像 镜像名:版本号/镜像id
docker rmi nginx:latest
- 启动容器
# -d:后台运行
# --restart=always: 开机自启
# 88:80 这是端口映射操作,规则 主机端口:容器端口
docker run --name=mynginx -d --restart=always -p 88:80 nginx
# 查看正在运行的容器
docker ps
# 查看所有
docker ps -a
# 删除停止的容器
docker rm 容器id/名字
#强制删除正在运行中的
docker rm -f mynginx
#停止容器
docker stop 容器id/名字
#再次启动
docker start 容器id/名字
#应用开机自启
docker update 容器id/名字 --restart=always
- 修改容器内容
进入容器内修改
# 进入容器内部的系统,修改容器内容
# dc4254016fe9:对应的容器ID,可在docker ps查看
docker exec -it dc4254016fe9 /bin/bash
修改完成以后,可以通过服务器的公网Ip:88方式访问,会发现写入的内容展现在页面。
通过外部挂载的方式修改
# -v 主机目录:容器目录:ro/rw表示操作权限
docker run --name=mynginx -d --restart=always -p 88:80 -v /data/html:/usr/share/nginx/html:ro nginx
# 挂载完成以后,就可以去主机的/data/html修改对应页面
- 提交容器的修改
# docker commit [OPTIONS] CONTAINER:容器ID [REPOSITORY[:TAG]]:镜像版本
docker commit -a "satoshi" -m "更新nginx首页" dc4254016fe9 mynginx:v1.0
提交以后可以通过命令查看,发现会有新的镜像出现。
- 镜像传输
# 将镜像保存成压缩包
docker save -o abc.tar mynginx:v1.0
# 别的机器加载这个镜像
docker load -i abc.tar
- 推送镜像到远端仓库
# 把旧镜像的名字,改成仓库要求的新版名字
docker tag mynginx:v1.0 satoshi/mynginx:v1.0
# 推送
docker push satoshi/mynginx:v1.0
# 登录到docker hub
docker login
# 推送完成镜像后退出
docker logout
# 别的机器下载
docker pull satoshi/mynginx:v1.0
- 补充
docker logs 容器名/id 排错
docker exec -it 容器id /bin/bash
# docker 经常修改nginx配置文件
docker run -d -p 80:80 \
-v /data/html:/usr/share/nginx/html:ro \
-v /data/conf/nginx.conf:/etc/nginx/nginx.conf \
--name mynginx-02 \
nginx
#把容器指定位置的东西复制出来
docker cp 5eff66eec7e1:/etc/nginx/nginx.conf /data/conf/nginx.conf
#把外面的内容复制到容器里面
docker cp /data/conf/nginx.conf 5eff66eec7e1:/etc/nginx/nginx.conf
进阶实战
以Java应用为例,创建自定义APP的镜像并发布。
- 安装Redis镜像
# 下载
docker pull redis
# 创建redis配置文件/data/redis/redis.conf,配置密码和开启AOF
# 创建redis数据文件夹/data/redis/data
# 启动redis容器
docker run -v /data/redis/redis.conf:/etc/redis/redis.conf \
-v /data/redis/data:/data \
-d --name myredis \
-p 6379:6379 \
redis:latest redis-server /etc/redis/redis.conf
- 创建一个简单的Spring Boot项目
// 用于访问Redis服务,记录接口的访问次数
@RestController
public class CountController {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@GetMapping("/hello")
public String hello(){
BoundValueOperations<String, String> stringStringBoundValueOperations = stringRedisTemplate.boundValueOps("visit-count");
Long increment = stringStringBoundValueOperations.increment();
return "【"+ increment +"】次访问";
}
}
# 配置redis参数
spring.redis.host=47.116.88.143
spring.redis.port=6379
spring.redis.password=qwe123456
- 编写DockerFile
# 构件java应用所需要的环境依赖-JDK,对应的image和tag可以在docker hub找到
FROM openjdk:8-jdk-slim
# maintainer标识作者
LABEL maintainer=satoshi
# copy命令标识在docker build的时候,需要将当前目录下target文件夹内的jar包复制到容器指定路径下
COPY target/*.jar /app.jar
# 这句标识启动该应用所需的命令(即运行jar包的命令)
ENTRYPOINT ["java","-jar","/app.jar"]
- 将对应的jar包和DockerFile文件上传到Docker服务器
- 上传完成以后执行docker build命令
# 命令尾部的 . 指定执行时的当前目录
# java-demo 镜像名
# v1.0 tag
docker build -t java-demo:v1.0 .
- 执行结果
ducker images查看构建结果 - 启动自定义的镜像
docker run -d -p 8080:8080 --name myjava-app java-demo:v1.0
- 页面验证结果
Kubernetes基础
k8s基本概念
是什么
k8s出现的背景
传统部署时代:
早期,各机构是在物理服务器上运行应用程序。 由于无法限制在物理服务器中运行的应用程序资源使用,因此会导致资源分配问题。
例如,如果在物理服务器上运行多个应用程序, 则可能会出现一个应用程序占用大部分资源的情况,而导致其他应用程序的性能下降。
一种解决方案是将每个应用程序都运行在不同的物理服务器上, 但是当某个应用程式资源利用率不高时,剩余资源无法被分配给其他应用程式,
而且维护许多物理服务器的成本很高。虚拟化部署时代:
因此,虚拟化技术被引入了。虚拟化技术允许你在单个物理服务器的 CPU 上运行多台虚拟机(VM)。 虚拟化能使应用程序在不同 VM之间被彼此隔离,且能提供一定程度的安全性, 因为一个应用程序的信息不能被另一应用程序随意访问。
虚拟化技术能够更好地利用物理服务器的资源,并且因为可轻松地添加或更新应用程序, 而因此可以具有更高的可伸缩性,以及降低硬件成本等等的好处。
每个 VM 是一台完整的计算机,在虚拟化硬件之上运行所有组件,包括其自己的操作系统(OS)。
容器部署时代:
容器类似于 VM,但是更宽松的隔离特性,使容器之间可以共享操作系统(OS)。 因此,容器比起 VM 被认为是更轻量级的。且与 VM类似,每个容器都具有自己的文件系统、CPU、内存、进程空间等。 由于它们与基础架构分离,因此可以跨云和 OS 发行版本进行移植。
容器因具有许多优势而变得流行起来。
下面列出的是容器的一些好处:敏捷应用程序的创建和部署:与使用 VM 镜像相比,提高了容器镜像创建的简便性和效率。
持续开发、集成和部署:通过快速简单的回滚(由于镜像不可变性), 提供可靠且频繁的容器镜像构建和部署。
关注开发与运维的分离:在构建、发布时创建应用程序容器镜像,而不是在部署时, 从而将应用程序与基础架构分离。 可观察性:不仅可以显示 OS级别的信息和指标,还可以显示应用程序的运行状况和其他指标信号。
跨开发、测试和生产的环境一致性:在笔记本计算机上也可以和在云中运行一样的应用程序。 跨云和操作系统发行版本的可移植性:可在Ubuntu、RHEL、CoreOS、本地、 Google Kubernetes Engine 和其他任何地方运行。
以应用程序为中心的管理:提高抽象级别,从在虚拟硬件上运行 OS 到使用逻辑资源在 OS 上运行应用程序。
松散耦合、分布式、弹性、解放的微服务:应用程序被分解成较小的独立部分, 并且可以动态部署和管理 - 而不是在一台大型单机上整体运行。
资源隔离:可预测的应用程序性能。 资源利用:高效率和高密度。
k8s的功能
容器是打包和运行应用程序的好方式。在生产环境中, 你需要管理运行着应用程序的容器,并确保服务不会下线。 例如,如果一个容器发生故障,则你需要启动另一个容器。 如果此行为交由给系统处理,是不是会更容易一些?
这就是 Kubernetes 要来做的事情! Kubernetes 为你提供了一个可弹性运行分布式系统的框架。 Kubernetes 会满足你的扩展要求、故障转移、部署模式等。 例如,Kubernetes 可以轻松管理系统的灰度部署。
Kubernetes 为你提供:
- 服务发现和负载均衡
Kubernetes 可以使用 DNS 名称或自己的 IP 地址来曝露容器。 如果进入容器的流量很大, Kubernetes 可以负载均衡并分配网络流量,从而使部署稳定。 - 存储编排
Kubernetes 允许你自动挂载你选择的存储系统,例如本地存储、公共云提供商等。 - 自动部署和回滚
你可以使用 Kubernetes 描述已部署容器的所需状态, 它可以以受控的速率将实际状态更改为期望状态。 例如,你可以自动化 Kubernetes 来为你的部署创建新容器, 删除现有容器并将它们的所有资源用于新容器。 - 自动完成装箱计算
Kubernetes 允许你指定每个容器所需 CPU 和内存(RAM)。 当容器指定了资源请求时,Kubernetes 可以做出更好的决策来为容器分配资源。 - 自我修复
Kubernetes 将重新启动失败的容器、替换容器、杀死不响应用户定义的运行状况检查的容器, 并且在准备好服务之前不将其通告给客户端。 - 密钥与配置管理
Kubernetes 允许你存储和管理敏感信息,例如密码、OAuth 令牌和 ssh 密钥。 你可以在不重建容器镜像的情况下部署和更新密钥和应用程序配置,也无需在堆栈配置中暴露密钥。
k8s架构
工作模式
N master节点+ N worker节点,N>=1
组件架构
- 集群交互:API Server
- 集群控制器:Control manager
- 新建任务调度器:Scheduler
- 集群后台键值数据库:ETCD
- 云提供商控制器:Cloud Control Manager
- 集群网络访问代理:Kube-proxy
- 容器生命周期管理和监控:Kubelet
kubernetes安装
申请三台云服务器(2核4G)、分配公网IP,并加入一个VPC。
安装docker
参考前面章节docker实战的docker安装
安装kubelet、kubeadm、kubectl
- 环境要求
● 一台兼容的 Linux 主机。Kubernetes 项目为基于 Debian 和 Red Hat 的 Linux 发行版以及一些不提供包管理器的发行版提供通用的指令
● 每台机器 2 GB 或更多的 RAM (如果少于这个数字将会影响你应用的运行内存) 2 CPU 核或更多
● 集群中的所有机器的网络彼此均能相互连接(公网和内网都可以)
● 节点之中不可以有重复的主机名、MAC 地址或 product_uuid。
● 开启机器上的某些端口。VPC组内互通
● 禁用交换分区。为了保证 kubelet 正常工作,你 必须 禁用交换分区。 - 基础操作
#各个机器设置自己的域名
hostnamectl set-hostname xxxx
# 将 SELinux 设置为 permissive 模式(相当于将其禁用)
sudo setenforce 0
sudo sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
#关闭swap
swapoff -a
sed -ri 's/.*swap.*/#&/' /etc/fstab
#允许 iptables 检查桥接流量
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
br_netfilter
EOF
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
- 安装kubelet、kubeadm、kubectl
cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=http://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=http://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg
http://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
exclude=kubelet kubeadm kubectl
EOF
sudo yum install -y kubelet-1.20.9 kubeadm-1.20.9 kubectl-1.20.9 --disableexcludes=kubernetes
sudo systemctl enable --now kubelet
kubelet 现在每隔几秒就会重启,因为它陷入了一个等待 kubeadm 指令的死循环
使用kubeadm引导集群
- 下载所需要的镜像
sudo tee ./images.sh <<-'EOF'
#!/bin/bash
images=(
kube-apiserver:v1.20.9
kube-proxy:v1.20.9
kube-controller-manager:v1.20.9
kube-scheduler:v1.20.9
coredns:1.7.0
etcd:3.4.13-0
pause:3.2
)
for imageName in ${images[@]} ; do
docker pull registry.cn-hangzhou.aliyuncs.com/lfy_k8s_images/$imageName
done
EOF
chmod +x ./images.sh && ./images.sh
- 初始化主节点
#所有机器添加master域名映射,以下需要修改为自己的
echo "你的节点内网IP cluster-endpoint" >> /etc/hosts
#主节点初始化
kubeadm init \
--apiserver-advertise-address=192.168.40.3 \
--control-plane-endpoint=cluster-endpoint \
--image-repository registry.cn-hangzhou.aliyuncs.com/lfy_k8s_images \
--kubernetes-version v1.20.9 \
--service-cidr=10.96.0.0/16 \
--pod-network-cidr=172.31.0.0/16
#配置要求:你的服务器内网IP网段、service-cidr、pod-network-cidr网络范围不重叠
- 执行结果
- 按照命令指示完成后续步骤
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
Alternatively, if you are the root user, you can run:
export KUBECONFIG=/etc/kubernetes/admin.conf
# 后续步骤二:配置pod 网络。这里选用calico
# calico
# curl https://docs.projectcalico.org/manifests/calico.yaml -O
# 注意,上面配置的--pod-network-cidr=172.31.0.0/16需要与calico.yaml 里面的CALICO_IPV4POOL_CIDR的value保持一致
# kubectl apply -f calico.yaml
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/
You can now join any number of control-plane nodes by copying certificate authorities
and service account keys on each node and then running the following as root:
# 后续步骤三:新的master节点加入k8s集群的方式
kubeadm join cluster-endpoint:6443 --token 6fd3kz.9wkpm4niy7euflzs \
--discovery-token-ca-cert-hash sha256:a5a159eb8504012c4caa7cfefe86964cca80a36d580ab6392db9ddcdbc9f293f \
--control-plane
Then you can join any number of worker nodes by running the following on each as root:
# 后续步骤三 新的worker节点加入集群的方式
kubeadm join cluster-endpoint:6443 --token 6fd3kz.9wkpm4niy7euflzs \
--discovery-token-ca-cert-hash sha256:a5a159eb8504012c4caa7cfefe86964cca80a36d580ab6392db9ddcdbc9f293f
#查看集群所有节点
kubectl get nodes
#根据配置文件,给集群创建资源
kubectl apply -f xxxx.yaml
#查看集群部署了哪些应用?
docker ps === kubectl get pods -A
# 运行中的应用在docker里面叫容器,在k8s里面叫Pod
kubectl get pods -A
- 安装完成以后验证集群状态
- 安装dashboard
kubernetes官方提供的可视化界面部署
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.3.1/aio/deploy/recommended.yaml
如果下载失败,可以直接使用以下的yml文件
# Copyright 2017 The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
apiVersion: v1
kind: Namespace
metadata:
name: kubernetes-dashboard
---
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kubernetes-dashboard
---
kind: Service
apiVersion: v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kubernetes-dashboard
spec:
ports:
- port: 443
targetPort: 8443
selector:
k8s-app: kubernetes-dashboard
---
apiVersion: v1
kind: Secret
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard-certs
namespace: kubernetes-dashboard
type: Opaque
---
apiVersion: v1
kind: Secret
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard-csrf
namespace: kubernetes-dashboard
type: Opaque
data:
csrf: ""
---
apiVersion: v1
kind: Secret
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard-key-holder
namespace: kubernetes-dashboard
type: Opaque
---
kind: ConfigMap
apiVersion: v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard-settings
namespace: kubernetes-dashboard
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kubernetes-dashboard
rules:
# Allow Dashboard to get, update and delete Dashboard exclusive secrets.
- apiGroups: [""]
resources: ["secrets"]
resourceNames: ["kubernetes-dashboard-key-holder", "kubernetes-dashboard-certs", "kubernetes-dashboard-csrf"]
verbs: ["get", "update", "delete"]
# Allow Dashboard to get and update 'kubernetes-dashboard-settings' config map.
- apiGroups: [""]
resources: ["configmaps"]
resourceNames: ["kubernetes-dashboard-settings"]
verbs: ["get", "update"]
# Allow Dashboard to get metrics.
- apiGroups: [""]
resources: ["services"]
resourceNames: ["heapster", "dashboard-metrics-scraper"]
verbs: ["proxy"]
- apiGroups: [""]
resources: ["services/proxy"]
resourceNames: ["heapster", "http:heapster:", "https:heapster:", "dashboard-metrics-scraper", "http:dashboard-metrics-scraper"]
verbs: ["get"]
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
rules:
# Allow Metrics Scraper to get metrics from the Metrics server
- apiGroups: ["metrics.k8s.io"]
resources: ["pods", "nodes"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kubernetes-dashboard
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: kubernetes-dashboard
subjects:
- kind: ServiceAccount
name: kubernetes-dashboard
namespace: kubernetes-dashboard
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: kubernetes-dashboard
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: kubernetes-dashboard
subjects:
- kind: ServiceAccount
name: kubernetes-dashboard
namespace: kubernetes-dashboard
---
kind: Deployment
apiVersion: apps/v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kubernetes-dashboard
spec:
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
k8s-app: kubernetes-dashboard
template:
metadata:
labels:
k8s-app: kubernetes-dashboard
spec:
containers:
- name: kubernetes-dashboard
image: kubernetesui/dashboard:v2.3.1
imagePullPolicy: Always
ports:
- containerPort: 8443
protocol: TCP
args:
- --auto-generate-certificates
- --namespace=kubernetes-dashboard
# Uncomment the following line to manually specify Kubernetes API server Host
# If not specified, Dashboard will attempt to auto discover the API server and connect
# to it. Uncomment only if the default does not work.
# - --apiserver-host=http://my-address:port
volumeMounts:
- name: kubernetes-dashboard-certs
mountPath: /certs
# Create on-disk volume to store exec logs
- mountPath: /tmp
name: tmp-volume
livenessProbe:
httpGet:
scheme: HTTPS
path: /
port: 8443
initialDelaySeconds: 30
timeoutSeconds: 30
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsUser: 1001
runAsGroup: 2001
volumes:
- name: kubernetes-dashboard-certs
secret:
secretName: kubernetes-dashboard-certs
- name: tmp-volume
emptyDir: {}
serviceAccountName: kubernetes-dashboard
nodeSelector:
"kubernetes.io/os": linux
# Comment the following tolerations if Dashboard must not be deployed on master
tolerations:
- key: node-role.kubernetes.io/master
effect: NoSchedule
---
kind: Service
apiVersion: v1
metadata:
labels:
k8s-app: dashboard-metrics-scraper
name: dashboard-metrics-scraper
namespace: kubernetes-dashboard
spec:
ports:
- port: 8000
targetPort: 8000
selector:
k8s-app: dashboard-metrics-scraper
---
kind: Deployment
apiVersion: apps/v1
metadata:
labels:
k8s-app: dashboard-metrics-scraper
name: dashboard-metrics-scraper
namespace: kubernetes-dashboard
spec:
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
k8s-app: dashboard-metrics-scraper
template:
metadata:
labels:
k8s-app: dashboard-metrics-scraper
annotations:
seccomp.security.alpha.kubernetes.io/pod: 'runtime/default'
spec:
containers:
- name: dashboard-metrics-scraper
image: kubernetesui/metrics-scraper:v1.0.6
ports:
- containerPort: 8000
protocol: TCP
livenessProbe:
httpGet:
scheme: HTTP
path: /
port: 8000
initialDelaySeconds: 30
timeoutSeconds: 30
volumeMounts:
- mountPath: /tmp
name: tmp-volume
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsUser: 1001
runAsGroup: 2001
serviceAccountName: kubernetes-dashboard
nodeSelector:
"kubernetes.io/os": linux
# Comment the following tolerations if Dashboard must not be deployed on master
tolerations:
- key: node-role.kubernetes.io/master
effect: NoSchedule
volumes:
- name: tmp-volume
emptyDir: {}
设置访问端口
kubectl edit svc kubernetes-dashboard -n kubernetes-dashboard
# 进入编辑页面后,将type:ClusterIP改为NodePort
查看端口,配置安全组
kubectl get svc -A |grep kubernetes-dashboard
# 根据按照下图,需要配置开放31242端口
创建访问账户
#创建访问账号,准备一个yaml文件; vi dash-user.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: admin-user
namespace: kubernetes-dashboard
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: admin-user
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: admin-user
namespace: kubernetes-dashboard
# 应用该文件
kubectl apply -f dash-user.yaml
获取访问令牌
kubectl -n kubernetes-dashboard get secret $(kubectl -n kubernetes-dashboard get sa/admin-user -o jsonpath="{.secrets[0].name}") -o go-template="{{.data.token | base64decode}}"
# 这是Token
eyJhbGciOiJSUzI1NiIsImtpZCI6IkZkZ0k5WFRWbXo2b0FMb3RSVGlJclM3RWtKZFpRbGtPNXc5LUk0c3dvOVkifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlcm5ldGVzLWRhc2hib2FyZCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJhZG1pbi11c2VyLXRva2VuLTQ5N3RnIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6ImFkbWluLXVzZXIiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiIzODI5ODUxYi0xOTJmLTQxMGMtYjU4YS00MmRmZjgzNWJhNzAiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6a3ViZXJuZXRlcy1kYXNoYm9hcmQ6YWRtaW4tdXNlciJ9.G4W4TeCvI1g4r10WZhHMMuVeiTKeb0m3x5_kiAJfCz9EOKIcTXXKlUeQ1bjdPKNU9sXqmCg2vkQjkoFyMjHwok_zcEMV0DgraIdtrXWCiRZ3X0HY63O3kGmtVYlKwaqsIf7S65YlhOzN9cvRE1F8KS97XZDDvdnRagyB0wJ7u46r0TDDVxYfdHH-LkQn_9PGgn03Fou7keOWQDOYWypGFEHaKOjwsz-pKJEfTaT941QkWedXGr3ZX0zSX7t_6bq8AYlRXINWOU-fOr4fNOsfaZdG-zeSyaj4DfiXdDvLGazlT8Skz2j5iZXUgFzPgDPr58VXaaUOPQybVYzVI5JR2Q
输入Token即可进入Dashboard
k8s核心实战
资源创建方式
- 命令行
- YAML文件方式
Namespace
命名空间(Namespace)用于隔离资源,默认只隔离资源,不隔离网络。
- 命令行方式管理命名空间
# 创建
kubectl create ns hello
# 删除
kubectl delete ns hello
- YAML方式创建命名空间
apiVersion: v1
kind: Namespace
metadata:
name: hello
# 通过配置文件创建
kubectl apply -f hello.yaml
# 通过配置文件删除
kubectl delete -f hello.yaml
Pod
Pod标识一组运行中的容器,它是kubernetes中应用的最小单位。
不同Pod之间具有隔离性,同一个Pod内不同容器共享网络空间、存储、CPU等。
一个Pod内可运行多个应用(docker概念里面的多个容器)。
Pod名称不能重复。
# 命令行创建nginx pod
kubectl run mynginx --image=nginx
# 查看default名称空间的Pod
kubectl get pod
# 描述
kubectl describe pod 你自己的Pod名字
# 删除
kubectl delete pod Pod名字
# 查看Pod的运行日志
kubectl logs Pod名字
# 每个Pod - k8s都会分配一个ip
kubectl get pod -owide
# 使用Pod的ip+pod里面运行容器的端口
curl 192.168.169.136
# 集群中的任意一个机器以及任意的应用都能通过Pod分配的ip来访问这个Pod
- 以YAML方式创建Nginx Pod
apiVersion: v1
kind: Pod
metadata:
labels:
run: mynginx
name: mynginx
# namespace: default
spec:
containers:
- image: nginx
name: mynginx
- 以YAML方式创建Nginx + Tomcat Pod
apiVersion: v1
kind: Pod
metadata:
labels:
run: myapp
name: myapp
spec:
containers:
- image: nginx
name: nginx
- image: tomcat:8.5.68
name: tomcat
- 通过YAML删除对应的Pod
kubectl delete -f xxx.yaml
- 通过Dashboard创建Pod
- 通过Dashboard进入Pod命令行界面
- Pod界面一览
Deployment
控制Pod,使Pod拥有多副本,自愈,扩缩容等能力。
通过deployment方式创建的pod具有自愈能力(pod宕机、被人为关闭等异常时,deployment会自动拉起新的pod)
kubectl create deployment mytomcat --image=tomcat:8.5.68
- 多副本
命令行方式
kubectl create deployment my-dep --image=nginx --replicas=3
yaml方式
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: my-dep
name: my-dep
spec:
replicas: 3
selector:
matchLabels:
app: my-dep
template:
metadata:
labels:
app: my-dep
spec:
containers:
- image: nginx
name: nginx
- 扩缩容
# 从2扩到5
kubectl scale --replicas=5 deployment/my-dep
# 直接修改deployment文件的参数也可以实现扩容/缩容
kubectl edit deployment my-dep
# 从5缩到3
kubectl scale --replicas=3 deployment/my-dep
在可视化界面实现扩缩容
- 自愈、故障转移等
停机、删除Pod、容易崩溃等场景下,实现副本保证。 - 滚动更新(不停机更新)
kubectl set image deployment/my-dep nginx=nginx:1.16.1 --record
# 下面是打印滚动更新的实时状态
kubectl rollout status deployment/my-dep
滚动更新的操作,会逐个替换老的容器为新的容器,这个过程中如果新容器出现错误,则后续的更新不会继续。
- 版本回退
#历史记录
kubectl rollout history deployment/my-dep
#查看某个历史详情
kubectl rollout history deployment/my-dep --revision=2
#回滚(回到上次)
kubectl rollout undo deployment/my-dep
#回滚(回到指定版本)
kubectl rollout undo deployment/my-dep --to-revision=2
- 其他工作负载
除了Deployment,k8s还有 StatefulSet 、DaemonSet 、Job 等 类型资源。我们都称为 工作负载。有状态应用使用 StatefulSet 部署,无状态应用使用 Deployment 部署。
官方说明
Service
Pod的服务发现与负载均衡
- 配置ClusterIP方式(只能集群内访问)
yaml配置文件
apiVersion: v1
kind: Service
metadata:
labels:
app: my-dep
name: my-dep
spec:
selector:
app: my-dep
ports:
- port: 8000
protocol: TCP
targetPort: 80
- 通过命令行
# 等同于没有--type的
kubectl expose deployment my-dep --port=8000 --target-port=80 --type=ClusterIP
- 配置NodePort方式(外网可以访问)
yaml配置文件
apiVersion: v1
kind: Service
metadata:
labels:
app: my-dep
name: my-dep
spec:
ports:
- port: 8000
protocol: TCP
targetPort: 80
selector:
app: my-dep
type: NodePort
- 通过命令行方式
kubectl expose deployment my-dep --port=8000 --target-port=80 --type=NodePort
- 查看创建的service
kubectl get service
Ingress
安装
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v0.47.0/deploy/static/provider/baremetal/deploy.yaml
#修改镜像
vi deploy.yaml
#将image的值改为如下值:
registry.cn-hangzhou.aliyuncs.com/lfy_k8s_images/ingress-nginx-controller:v0.46.0
# 检查安装的结果
kubectl get pod,svc -n ingress-nginx
# 最后别忘记把svc暴露的端口要放行
使用
官方地址测试环境
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-server
spec:
replicas: 2
selector:
matchLabels:
app: hello-server
template:
metadata:
labels:
app: hello-server
spec:
containers:
- name: hello-server
image: registry.cn-hangzhou.aliyuncs.com/lfy_k8s_images/hello-server
ports:
- containerPort: 9000
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx-demo
name: nginx-demo
spec:
replicas: 2
selector:
matchLabels:
app: nginx-demo
template:
metadata:
labels:
app: nginx-demo
spec:
containers:
- image: nginx
name: nginx
---
apiVersion: v1
kind: Service
metadata:
labels:
app: nginx-demo
name: nginx-demo
spec:
selector:
app: nginx-demo
ports:
- port: 8000
protocol: TCP
targetPort: 80
---
apiVersion: v1
kind: Service
metadata:
labels:
app: hello-server
name: hello-server
spec:
selector:
app: hello-server
ports:
- port: 8000
protocol: TCP
targetPort: 9000
ingress配置
- 域名访问
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-host-bar
spec:
ingressClassName: nginx
rules:
- host: "hello.atguigu.com"
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: hello-server
port:
number: 8000
- host: "demo.atguigu.com"
http:
paths:
- pathType: Prefix
path: "/nginx" # 把请求会转给下面的服务,下面的服务一定要能处理这个路径,不能处理就是404
backend:
service:
name: nginx-demo ## java,比如使用路径重写,去掉前缀nginx
port:
number: 8000
- 路径重写
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
name: ingress-host-bar
spec:
ingressClassName: nginx
rules:
- host: "hello.atguigu.com"
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: hello-server
port:
number: 8000
- host: "demo.atguigu.com"
http:
paths:
- pathType: Prefix
path: "/nginx(/|$)(.*)" # 把请求会转给下面的服务,下面的服务一定要能处理这个路径,不能处理就是404
backend:
service:
name: nginx-demo ## java,比如使用路径重写,去掉前缀nginx
port:
number: 8000
- 流量限制
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-limit-rate
annotations:
nginx.ingress.kubernetes.io/limit-rps: "1"
spec:
ingressClassName: nginx
rules:
- host: "haha.atguigu.com"
http:
paths:
- pathType: Exact
path: "/"
backend:
service:
name: nginx-demo
port:
number: 8000
存储抽象
环境准备
以NFS作为底层存储服务。
- 所有节点安装
#所有机器安装
yum install -y nfs-utils
- 主节点配置
#nfs主节点
echo "/nfs/data/ *(insecure,rw,sync,no_root_squash)" > /etc/exports
mkdir -p /nfs/data
systemctl enable rpcbind --now
systemctl enable nfs-server --now
#配置生效
exportfs -r
- 从节点执行挂载
# 查看可挂载目录
showmount -e 172.31.0.4
#执行以下命令挂载 nfs 服务器上的共享目录到本机路径 /root/nfsmount
mkdir -p /nfs/data
mount -t nfs 172.31.0.4:/nfs/data /nfs/data
# 写入一个测试文件
echo "hello nfs server" > /nfs/data/test.txt
存储挂载
- 原生挂载方式
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx-pv-demo
name: nginx-pv-demo
spec:
replicas: 2
selector:
matchLabels:
app: nginx-pv-demo
template:
metadata:
labels:
app: nginx-pv-demo
spec:
containers:
- image: nginx
name: nginx
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
volumes:
- name: html
nfs:
server: 172.31.0.4
path: /nfs/data/nginx-pv
- PV&PVC
PV:持久卷(Persistent Volume),将应用需要持久化的数据保存到指定位置
PVC:持久卷申明(Persistent Volume Claim),申明需要使用的持久卷规格
- 创建静态PV池
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv01-10m
spec:
capacity:
storage: 10M
accessModes:
- ReadWriteMany
storageClassName: nfs
nfs:
path: /nfs/data/01
server: 172.31.0.4
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv02-1gi
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteMany
storageClassName: nfs
nfs:
path: /nfs/data/02
server: 172.31.0.4
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv03-3gi
spec:
capacity:
storage: 3Gi
accessModes:
- ReadWriteMany
storageClassName: nfs
nfs:
path: /nfs/data/03
server: 172.31.0.4
kubectl apply -f xxx-pv.yaml
创建PVC
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: nginx-pvc
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 200Mi
storageClassName: nfs
绑定PVC
kubectl apply -f xxx-pvc.yaml
创建Pod绑定PVC
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx-deploy-pvc
name: nginx-deploy-pvc
spec:
replicas: 2
selector:
matchLabels:
app: nginx-deploy-pvc
template:
metadata:
labels:
app: nginx-deploy-pvc
spec:
containers:
- image: nginx
name: nginx
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
volumes:
- name: html
persistentVolumeClaim:
claimName: nginx-pvc
- ConfigMap
抽取应用配置,并且可以自动更新
以Redis为例子
# 创建配置,redis保存到k8s的etcd;
kubectl create cm redis-conf --from-file=redis.conf
# 该yaml文件可以以命令行的方式获取
# kubectl get cm redis-conf --oyaml
apiVersion: v1
data: #data是所有真正的数据,key:默认是文件名 value:配置文件的内容
redis.conf: |
appendonly yes
kind: ConfigMap
metadata:
name: redis-conf
namespace: default
创建Pod
apiVersion: v1
kind: Pod
metadata:
name: redis
spec:
containers:
- name: redis
image: redis
command:
- redis-server
- "/redis-master/redis.conf" #指的是redis容器内部的位置
ports:
- containerPort: 6379
volumeMounts:
- mountPath: /data
name: data
- mountPath: /redis-master
name: config
volumes:
- name: data
emptyDir: {}
- name: config
configMap:
name: redis-conf
items:
- key: redis.conf
path: redis.conf
检查默认配置
kubectl exec -it redis -- redis-cli
127.0.0.1:6379> CONFIG GET appendonly
127.0.0.1:6379> CONFIG GET requirepass
修改ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: example-redis-config
data:
redis-config: |
maxmemory 2mb
maxmemory-policy allkeys-lru
检查更新
kubectl exec -it redis -- redis-cli
127.0.0.1:6379> CONFIG GET maxmemory
127.0.0.1:6379> CONFIG GET maxmemory-policy
- Secret
Secret 对象类型用来保存敏感信息,例如密码、OAuth 令牌和 SSH 密钥。 将这些信息放在 secret 中比放在 Pod的定义或者 容器镜像 中来说更加安全和灵活。
kubectl create secret docker-registry leifengyang-docker \
--docker-username=leifengyang \
--docker-password=Lfy123456 \
--docker-email=534096094@qq.com
##命令格式
kubectl create secret docker-registry regcred \
--docker-server=<你的镜像仓库服务器> \
--docker-username=<你的用户名> \
--docker-password=<你的密码> \
--docker-email=<你的邮箱地址>
apiVersion: v1
kind: Pod
metadata:
name: private-nginx
spec:
containers:
- name: private-nginx
image: leifengyang/guignginx:v1.0
imagePullSecrets:
- name: leifengyang-docker