参考文档
https://www.yuque.com/leifengyang/oncloud/ctiwgo
基础概念
公有云、私有云概念、混合云
云平台实战
开通阿里云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