技术标签: 云原生 kubernetes Docker 容器
1、准备好三台虚拟机(基于VMWare centos7)
【临时关闭】
systemctl stop fire walld
【永久关闭】
systemctl disable firewalld
【永久关闭】
sed -i 's/enforcing/disabled/' '/etc/selinux/config'
临时关闭
setenforce 0
【临时关闭】
swapoff -a
【永久关闭】
sed -ri 's/.*swap.*/#&/' /etc/fstab
hostnamectl set-hostname <hostname>
比如设置名字
k8master
k8node1
k8node2
cat >> /etc/hosts<<EOF
192.168.12.151 k8node2
192.168.12.152 k8node1
192.168.12.153 k8master
EOF
cat >/etc/sysctl.d/k8s.conf <<EOF
net.bridge.bridge-nf-call-ip6tables=1
net.bridge.bridge-nf-call-iptables=1
EOF
yum install -y ntpdate
ntpdate time.windows.com
2、每台机器安装 docker、kubeadmin、kubelet,建立起集群
第一步:先搞docker:
docker安装
注意还要把 docker.serivce 加入到开机启动:
systemctl enable docker.service
第二步:还是添加个阿里云的yum源【master work 都要搞】
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=1
repo_gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
第三步:再装kubeadmin 、kubeadmin 、kubectl 【master work 都要装】
yum install -y kubelet-1.18.0
yum install -y kubeadm-1.18.0
yum install -y kubectl-1.18.0
systemctl enable kubelet
【设置了开机启动】
第四步:部署k8 master节点(在k8master节点上执行初始化动作)
这里的 192.168.12.153 是我本地虚拟机的 ip,即master
kubeadm init \
--apiserver-advertise-address=192.168.12.153 \
--image-repository registry.aliyuncs.com/google_containers \
--kubernetes-version v1.18.0 \
--service-cidr=10.1.0.0/16 \
--pod-network-cidr=10.244.0.0/16
等到第四步执行完,这个过程会比较久,它会把master node上所需要的scheduler 、 apiserver 等N多东西拉取下来(如果不是阿里云的镜像,估计根本没法玩。。)等到出现下面的语句时就表示执行成功了
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.12.153:6443 --token b4ee7o.2d8puhdflaonjq38 \
--discovery-token-ca-cert-hash sha256:16526f83d2ae995ab96544b4f355ec5e3cba4cacc334c67035afa27e0ea9088d
第五步: 上面一步的执行结果中已经说明了下一步的动作。
配置:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
第六步:部署work node节点,将其 join到集群中来 【注意:要在work node执行】
kubeadm join 192.168.12.153:6443 --token b4ee7o.2d8puhdflaonjq38 \
--discovery-token-ca-cert-hash sha256:16526f83d2ae995ab96544b4f355ec5e3cba4cacc334c67035afa27e0ea9088d
这里的token是24H后失效,但可以重新生成:
kubeadm token create --print-join-command
做到这里,看看 此时状态–> NotReady
[root@k8master ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8master NotReady master 9h v1.18.0
k8node1 NotReady <none> 54s v1.18.0
k8node2 NotReady <none> 39s v1.18.0
第七步:部署CNI网络插件,否则没法联网 【在master上执行】
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
不过这个地址要翻墙,有点麻烦。可以先下载下来【点此查看】,然后执行
kubectl apply -f kube-flannel.yml
第八步:查看此时 pod 的状态
[root@k8master ~]# kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-7ff77c879f-px8zm 1/1 Running 0 10h
coredns-7ff77c879f-tqtjt 1/1 Running 0 10h
etcd-k8master 1/1 Running 1 10h
kube-apiserver-k8master 1/1 Running 1 10h
kube-controller-manager-k8master 1/1 Running 1 10h
kube-flannel-ds-hzks4 1/1 Running 0 83m
kube-flannel-ds-kcpk9 1/1 Running 0 83m
kube-flannel-ds-mflpz 1/1 Running 0 83m
kube-proxy-rggn5 1/1 Running 1 10h
kube-proxy-rz5b4 1/1 Running 0 106m
kube-proxy-w5rfq 1/1 Running 0 106m
kube-scheduler-k8master 1/1 Running 1 10h
第九步:安装一个Nginx 来做个测试(主要看网络有没问题)
kubectl create deployment nginx --image=nginx
获取到镜像可能需要时间,可以 不断 执行下面命令查看状态
kubectl get pod
kubectl expose deployment nginx --port=80 --type=NodePort
【查看Pod状态,注意这里是 逗号】
kubectl get pod,svc
[root@k8master ~]# kubectl get pod,svc
NAME READY STATUS RESTARTS AGE
pod/nginx-f89759699-pchp4 1/1 Running 0 20m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.1.0.1 <none> 443/TCP 10h
service/nginx NodePort 10.1.114.75 <none> 80:31787/TCP 16m
通过浏览器访问:
http://192.168.12.151:31787/
OR:
http://192.168.12.152:31787/
由于K8做了LB,任意一个Work Node 的节点都可以访问到 Nginx的欢迎页面。
TODO
单节点集群:一个控制节点和一个工作节点,是个玩具。
最小的生产环境集群:至少三个节点,包括一个控制节点和两个工作节点,提供一定程度的高可用性和容错性。
建议的生产环境集群:至少三个控制节点(master)和三个worker node,可根据需求和负载进行扩展
基本格式: kubectl [command] [type] [name] [flags]
[root@k8master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-f89759699-pchp4 1/1 Running 0 51m
帮助命令:
kubectl help
【Kubectl 的命令 特别多,需要的时候直接查阅 帮助文档即可】kubectl get --help
【看 get 的细致命令】查看 健康检查:
kubectl get cs
yml文件格式:
---
表示一个新yml 的开始yml文件我们基本不从0开始写,而是生成一个模板,然后自己改改。
kubectl create deployment web --image=nginx -o yaml --dry-run > myyaml.yaml
这里创建一个 资源名为web的部署,但是并不真正执行,而只是 产生一个 yaml, --dry-run 表示 尝试运行;生成的yaml 内容输出到 一个文件
[root@k8master ~]# cat myyaml.yaml
# 版本
apiVersion: apps/v1
# 资源类型
kind: Deployment
# 资源元数据
metadata:
creationTimestamp: null
labels:
app: web
name: web
# 资源规格
spec:
# 副本数量
replicas: 1
# 标签选择器
selector:
matchLabels:
app: web
strategy: {}
# pod 模板
template:
# pod 元数据
metadata:
creationTimestamp: null
labels:
app: web
# pod规格
spec:
# 容器配置
containers:
- image: nginx
name: nginx
resources: {}
status: {}
kubectl get deploy nginx -o=yaml > myyaml2.yaml
创建容器使用Docker,一个Docker对应一个容器,一个容器里只有一个进程(多进程似乎也能实现,但不好管理),一个容器运行一个程序
Pod 为方便管理,将多个容器放在一起。Pod是多进程设计。
Pod存在是为了亲密性应用: 两个应用之间需要频繁调用。应用由于在同一网络中,调用性能更好、当然也更方便。
两个大机制:共享网络+共享存储 。
首先看第一点:
再看第二点:共享存储
就是 volume 数据卷的作用了
1、镜像拉取
2、资源限制
3、 重启策略
K8 的hc 是 容器对应用的hc,如此hc 有个问题:比如Java应用,已经堆溢出了,已不能提供服务,但是进程还在,容器不能准确获取状态。有一种更好的思路是通过检查应用状态来获取准确状态
先看 这里: 这个Pod是怎么 在 k8node1 上创建的呢?
比如:
resources:
requests:
memory:'64Mi'
cpu:'250m'
说明了宿主机必须满足剩余memory 64M,CPU 0.25C才会被调度到
比如yml 有这么一段描述:指定了Pod应该在 env_role=dev的Node上
下面简单描述一下 nodeSelector怎么对 env_role 起作用。Node1 Node2 属于dev ,Node3 Node4属于prod,可以调度Pod在 prod 环境中落地。这个场景对多环境的支持很有用。日常开发中常会切换dev qa staging等多个环境,但可能只要一套k8就将所有主机管理起来了。
那如何打标签呢?
[root@k8master ~]# kubectl label node k8node1 env_role=dev
node/k8node1 labeled
[root@k8master ~]# kubectl get nodes k8node1 --show-labels
NAME STATUS ROLES AGE VERSION LABELS
k8node1 Ready <none> 47h v1.18.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,env_role=dev,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8node1,kubernetes.io/os=linux
默认已经打了很多标签了。env_role只是一个标签名,我们可以打自定义的标签,比如 kubectl label node k8node foo=bar
nodeAffinity
,和nodeSelector
实现方式一致,使用labels
来影响调度。nodeAffinity
支持运算符操作,支持两种 亲和性(硬 、软)。常用operator: In NotIn Exists Gt Lt DoesnotExist
。
比如, 在nodeSelector
中,要求调度到env_role=dev
的节点,若有该label
的节点不存在,将会一直等待。使用nodeAffinity(软)
,我们可以设定优先调度到 env_role=dev
,若没有,调度到env_role=qa 也可以。
也有所谓的反亲和性,截图中使用的是 operator :In,如果是 NotIn DoesnotExist
,就是反亲和。
p.s. 英语中的 affinity 表示一种亲密程度,也常见词,翻译成了汉语之后,总感觉有点过于高大上了,尽管它表达的是很简单的含义。
NodeSelector NodeAffinity 都是Pod的属性,在调度的时候实现。
污点:不是Pod的属性,而是节点的属性,规定哪些节点不做普通分配调度。
使用场景:
演示:
[root@k8master ~]# kubectl describe node k8master |grep taint -i
Taints: node-role.kubernetes.io/master:NoSchedule
这里是master:NoSchedule;K8中的污点值的枚举(三个):
如何打上污点呢?
kubectl taint node [node] key=value:污点枚举值
kubectl taint node [node] key=value:污点枚举值 -
举个栗子:
// 创建 nginx 应用
[root@k8master ~]# kubectl create deployment web --image=nginx
deployment.apps/web created
//看此时pods
[root@k8master ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-f89759699-pchp4 1/1 Running 0 2d11h 10.244.1.2 k8node1 <none> <none>
web-5dcb957ccc-2gbcj 1/1 Running 0 40s 10.244.2.2 k8node2 <none> <none>
// 再部署多一个nginx (名字叫 web)
kubectl create deployment web --image=nginx
// 再跟着扩容一个
kubectl scale deployment web --replicas=2
// 此时再看 pod情况
[root@k8master ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-f89759699-pchp4 1/1 Running 0 2d11h 10.244.1.2 k8node1 <none> <none>
web-5dcb957ccc-2gbcj 1/1 Running 0 9m13s 10.244.2.2 k8node2 <none> <none>
web-5dcb957ccc-8wnn4 1/1 Running 0 2m56s 10.244.1.3 k8node1 <none> <none>
// 看到 Pod在Node上:
无论是 k8node1 k8node2都有分布。
// 删除当前的 Pods
[root@k8master ~]# kubectl delete deployment nginx
[root@k8master ~]# kubectl delete deployment web
// 所有pod 已经删除完了
[root@k8master ~]# kubectl get pods -o wide
No resources found in default namespace.
// 给 k8node1 打上污点
[root@k8master ~]# kubectl taint node k8node1 env_role=dev:NoSchedule
node/k8node1 tainted
// 确认已经打上了污点
[root@k8master ~]# kubectl describe node k8node1 |grep -i taint
Taints: env_role=dev:NoSchedule
// 创建并扩容
[root@k8master ~]# kubectl create deployment web --image=nginx
deployment.apps/web created
[root@k8master ~]# kubectl scale deployment web --replicas=2
deployment.apps/web scaled
// 可以看到 所有的容器都部署到了 k8node2 ,k8node1 由于已经打上了污点,因此不会被调度到
[root@k8master ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-5dcb957ccc-ph7kd 1/1 Running 0 116s 10.244.2.4 k8node2 <none> <none>
web-5dcb957ccc-wtmcz 1/1 Running 0 2m14s 10.244.2.3 k8node2 <none> <none>
// 再来删除污点 【注意最后的 横杠 - 】
[root@k8master ~]# kubectl taint node k8node1 env_role:NoSchedule-
node/k8node1 untainted
[root@k8master ~]# kubectl describe node k8node1 |grep taint -i
Taints: <none>
污点容忍:
即使设置了污点值为 NoSchedule,这个Node依然可能被调度到。
Pod是一种 抽象; Controller 是具体存在的。
controller:
第一步: 先生成一个测试用的模板 yml:
W0309 22:37:13.728646 40038 helpers.go:553] --dry-run is deprecated and can be replaced with --dry-run=client.
[root@k8master ~]# cat web.yml
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: web
name: web
spec:
replicas: 1
selector:
matchLabels:
app: web
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: web
spec:
containers:
- image: nginx
name: nginx
resources: {}
status: {}
第二步:部署
由于是测试,不需要改了,然后从这个yaml 部署:
[root@k8master ~]# kubectl apply -f web.yml
deployment.apps/web created
[root@k8master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
web-5dcb957ccc-cfbw4 1/1 Running 0 13s
第三步: 暴露端口 (使用yml的方式)
// 生成暴露端口的yml
[root@k8master ~]# kubectl expose deployment web --port=80 --target-port=80 --type=NodePort --name=web1 -o yaml>web1.yml
// 看下web1.yml内容
[root@k8master ~]# cat service.yaml
apiVersion: v1
kind: Service
metadata:
creationTimestamp: null
labels:
app: web
name: web
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: web
status:
loadBalancer: {}
//应用yml暴露端口
[root@k8master ~]# kubectl apply -f web1.yml
// 查看是否暴露成功
[root@k8master ~]# kubectl get pod,svc
NAME READY STATUS RESTARTS AGE
pod/web-5dcb957ccc-cfbw4 1/1 Running 0 5m11s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.1.0.1 <none> 443/TCP 2d23h
service/web1 NodePort 10.1.72.70 <none> 80:31800/TCP 63s
// 从浏览器访问
OK
小结一下就是:
生成拉起容器yml --> 部署(拉起容器) --> 生成暴露端口 yml --> apply
roll : ngnix 1.14 --> 1.15
roll back: nginx :1.15--> 1.14
升级和回滚,不过回滚未必是从高版本–> 低版本,而是从当前版本–> 上一个版本。这里明白就好,不纠结。
k8可以使用yml 描述 升级和回滚的 行为:
(还是上一节生成的yml)
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: web
name: web
spec:
# 【这里改为 2】
replicas: 2
selector:
matchLabels:
app: web
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: web
spec:
containers:
# 【原本这里未指定版本因此使用了latest 版本,现在改为 1.14】
- image: nginx:1.14
name: nginx
resources: {}
status: {}
现在我们来升级一下 nginx 版本, nginx :1.15
// 通过 kubectl set image 来设定镜像版本
[root@k8master ~]# kubectl set image deployment web nginx=nginx:1.15
deployment.apps/web image updated
[root@k8master ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-65b7447c7-k5z87 0/1 Terminating 0 5m14s 10.244.1.5 k8node1 <none> <none>
web-65b7447c7-wr9k8 1/1 Running 0 5m14s 10.244.2.6 k8node2 <none> <none>
web-7d9697b7f8-6h4b6 0/1 ContainerCreating 0 2s <none> k8node2 <none> <none>
web-7d9697b7f8-ln4bb 1/1 Running 0 36s 10.244.1.6 k8node1 <none> <none>
// 看下 升级的状态
[root@k8master ~]# kubectl rollout status deployment web
deployment "web" successfully rolled out
看 升级的过程也挺有意思:先拉起一个容器,然后再销毁之前的容器。
如果此时我还是觉得之前的版本更好,想要还原回去;首先看下之前使用过哪些版本; 然后回滚到上一个版本(绝大多数场景下都是回滚到上一个版本)
// 看到目前只有过 2 个版本
[root@k8master ~]# kubectl rollout history deployment web
deployment.apps/web
REVISION CHANGE-CAUSE
1 <none>
2 <none>
[root@k8master ~]# kubectl rollout undo deployment web
deployment.apps/web rolled back
[root@k8master ~]# kubectl rollout status deployment web
deployment "web" successfully rolled out
// 回滚是个相当快的操作!!!
[root@k8master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
web-65b7447c7-9gxlr 1/1 Running 0 30s
web-65b7447c7-q7qx2 1/1 Running 0 27s
// 还可以回滚到指定的版本【注意后面的 --to-revision=2】:
[root@k8master ~]# kubectl rollout undo deployment web --to-revision=2
deployment.apps/web rolled back
[root@k8master ~]# kubectl rollout status deployment web
deployment "web" successfully rolled out
[root@k8master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
web-7d9697b7f8-qls7t 1/1 Running 0 15s
web-7d9697b7f8-s8cvk 1/1 Running 0 17s
弹性伸缩:
// 【将副本数修改为 5 个 (伸)】
[root@k8master ~]# kubectl scale deployment web --replicas=5
deployment.apps/web scaled
[root@k8master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
web-7d9697b7f8-5t8kp 1/1 Running 0 6s
web-7d9697b7f8-5ts25 1/1 Running 0 6s
web-7d9697b7f8-pmckl 1/1 Running 0 6s
web-7d9697b7f8-qls7t 1/1 Running 0 2m9s
web-7d9697b7f8-s8cvk 1/1 Running 0 2m11s
// 【将副本数 修改为 2 个(缩)】 (伸缩的过程极快)
[root@k8master ~]# kubectl scale deployment web --replicas=2
deployment.apps/web scaled
[root@k8master ~]#
[root@k8master ~]#
[root@k8master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
web-7d9697b7f8-pmckl 1/1 Running 0 102s
web-7d9697b7f8-qls7t 1/1 Running 0 3m45s
Service: 定义一组Pod的访问规则。
1、 为何需要service 这层抽象?
2、Service 和Pod 如何产生联系?
答曰:通过 labels & selector.
pod 具有 labels ;
serivce 有 selector:
serivce 使用 selector 来pick 哪些 pod 作为一组服务。
通过service实现服务注册和发现
3、常见service类型
先来看个例子:
kubectl expose --help
--type='': Type for this service: ClusterIP, NodePort, LoadBalancer, or ExternalName. Default is 'ClusterIP'.
这里看出来 service 的几种类型: clusterIP 、NodePort、LoadBalancer。
看下效果:
kubectl create deployment web --image=nginx --dry-run -o yaml > web.yaml
kubectl apply -f web.yaml
kubectl expose deployment web --port=80 --target-port=80 --dry-run -o yaml > service.yaml
// service中没有指定service 类型,则按 ClusterIP 处理
kubectl apply -f service.yaml
// 现在来看下pods,svc:
[root@k8master ~]# kubectl get pods,svc
NAME READY STATUS RESTARTS AGE
pod/web-5dcb957ccc-mprzn 1/1 Running 0 10m
pod/web-5dcb957ccc-s4jg8 1/1 Running 0 10m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.1.0.1 <none> 443/TCP 4d8h
service/web ClusterIP 10.1.143.33 <none> 80/TCP 2m38s
这里的 TYPE \ CLUSTER-IP 10.1.143.33 就是 前面说的用于集群内的service 类型,来测试下:
[root@k8master ~]# curl 10.1.143.33
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
.....
// 接着修改 service.yaml ; 增加了 service 类型为NodePort ;同时将 name 改为 web1(防止冲突)
[root@k8master ~]# cat service.yaml
apiVersion: v1
kind: Service
metadata:
creationTimestamp: null
labels:
app: web
name: web1
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: web
type: NodePort
status:
loadBalancer: {}
// 再来看此时 pods svc
[root@k8master ~]# kubectl get pods,svc
NAME READY STATUS RESTARTS AGE
pod/web-5dcb957ccc-mprzn 1/1 Running 0 17m
pod/web-5dcb957ccc-s4jg8 1/1 Running 0 17m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.1.0.1 <none> 443/TCP 4d8h
service/web ClusterIP 10.1.143.33 <none> 80/TCP 10m
service/web1 NodePort 10.1.128.23 <none> 80:30762/TCP 87s
发现多出了一个service Type: NodePort,我们可从浏览器访问:
http://192.168.12.151:30762/ ,访问OK
无状态:
状态:
什么叫 无头 的?
其实说白了:ClusterIP=None的service,取而代之的是 域名,即:通过域名来操作。
比如说,正常情况下是 有头的 service。
[root@k8master ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.1.0.1 <none> 443/TCP 6d12h
web ClusterIP 10.1.143.33 <none> 80/TCP 2d3h
web1 NodePort 10.1.128.23 <none> 80:30762/TCP 2d3h
1、准备个yml
[root@k8master ~]# cat sts.yml
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
apps: nginx
spec:
ports:
- port: 80
name: web
# 这里就是设置的无头的Service
clusterIP: None
selector:
app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: nginx-statefulset
namespace: default
spec:
serviceName: nginx
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
2、查看此时pods,svc
// 可以看到 : 有三个POD,每个都是唯一的名称
[root@k8master ~]# kubectl get pods,svc
NAME READY STATUS RESTARTS AGE
pod/nginx-statefulset-0 1/1 Running 0 31s
pod/nginx-statefulset-1 1/1 Running 0 27s
pod/nginx-statefulset-2 1/1 Running 0 23s
// 【下面的 Service/Nginx 是无头的的service】
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.1.0.1 <none> 443/TCP 7d8h
service/nginx ClusterIP None <none> 80/TCP 3m24s
前面提到: StatefulSet 的POD有唯一的网络标识,因此和Deployment相比,POD是有身份的。那域名怎么定义的呢?
答曰: 根据主机名,并根据一定规则生成域名
ngnix-statefulset-0.nginx.default.svc.cluster.local
特点:在每个Node节点上,运行同一个POD。新加入的Node,也加入这个POD。
这种部署方式十分常见:
做个演示:
1、准备yml
[root@k8master ~]# cat ds.yml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: mydaemonset
labels:
app: filebeat
spec:
selector:
matchLabels:
app: filebeat
template:
metadata:
labels:
app: filebeat
spec:
containers:
- name: logs
image: nginx
ports:
- containerPort: 80
volumeMounts:
- name: varlog
mountPath: /tmp/log
volumes:
- name: varlog
hostPath:
path: /var/log
2、查看
[root@k8master ~]# kubectl apply -f ds.yml
[root@k8master ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
mydaemonset-cl847 1/1 Running 0 28s 10.244.2.16 k8node2 <none> <none>
mydaemonset-vwk8v 1/1 Running 0 28s 10.244.1.17 k8node1 <none> <none>
// 去看一下创建的 daemonset ,果然里面有很多的日志了
[root@k8master ~]# kubectl exec -it mydaemonset-cl847 bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@mydaemonset-cl847:/# ls /tmp/log/
anaconda btmp dmesg maillog-20210307 rhsm spooler-20210314 vmware-network.log
......
首先,创建yml
apiVersion: batch/v1
kind: Job
metadata:
name: pi
spec:
template:
spec:
containers:
- name: pi
image: perl
command: ["perl","-Mbignum=bpi","-wle","print bpi(2000)"]
restartPolicy: Never
backoffLimit: 4
然后启动任务:
[root@k8master ~]# kubectl create -f job.yml
若果本地没有镜像,首先要拉取镜像,会比较慢;过了一段时间后,注意这里的状态,是 Completed,表示已经完成了;还可以 kubectl logs PODNAME
查看日志。
[root@k8master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
pi-5x67j 0/1 Completed 0 3m4s
[root@k8master ~]# kubectl logs pi-5x67j
3.14159...
[root@k8master ~]# cat cronjob.yml
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: hello
spec:
schedule: "*/1 * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: hello
image: busybox
args:
- /bin/sh
- -c
- date; echo hello from K8S cluster
restartPolicy: OnFailure
[root@k8master ~]# kubectl apply -f cronjob.yml
//等待一段时间后;可见,这个cron job ,每分钟都会起一个容器,执行完之后,就销毁容器!!!
[root@k8master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
hello-1616077920-2vf94 0/1 Completed 0 2m39s
hello-1616077980-4tvdx 0/1 Completed 0 99s
hello-1616078040-4t2bt 0/1 Completed 0 39s
部署无状态: Deployment
部署有状态: StatefulSet
部署 Job: Job
部署CronJob: CronJob
部署守护进程: DaemontSet
文章浏览阅读358次。虽然仪表这两个指标都是同时提升的,但是我的感觉准确度是更重要的,对于一个恒定不变的电流或电压的测量,仪表的显示是以准确度相当的噪声变化得到测量结果,而不是以分辨率量级的变化。如果一个表,多配几个显示的管子显示,完全可以做出来8位半甚至9位半的超级仪表,但实际效果也许还不如一个5、6位半的表。_7位半数字电压表3706中文使用手册
文章浏览阅读1.9k次。其中 -DLLVM_ENABLE_RTTI=ON 这个选项需要重点说明一下。由于我的目的是为了研究bpf技术,所以不可避免的会涉及到编译安装bpftrace这个工具。在编译bpftrace工程的时候如果没有打开 LLVM 的RTTI,会导致编译失败。而这个编译选项默认是关闭的,所以这里必须明确打开这个功能。这个python版本要求至少3.6以上,不然会报如下错误。clang 13.0.1 安装成功。1、LLVM所有版本下载路径。2、这里安装版本13.0.1。我这个编译4个小时左右完成。_centos7 clang
文章浏览阅读300次。分享职场生活、职场攻略、程序员创业资源,为一线开发者提供优质内容有一位java求职者,三年工作经验,面试时问到VO和DTO有什么区别,他回答不出来,知识面挺广的,就是不够深入,薪资要1..._不喜欢dto
文章浏览阅读3.3k次。//// do_IRQ 函数执行完硬件 ISR 后退出时调用此函数。//void irq_exit(void){ account_system_vtime(current); trace_hardirq_exit(); sub_preempt_count(IRQ_EXIT_OFFSET); //_do_irq
文章浏览阅读252次。原标题:一道经典的Python数据分析笔试题最近无意看到一份关于数据分析的Python笔试题,做起来还是很有意思的,特意自己动手做了一下,和大家分享一下,希望大家也可以跟着练习。题目如下: 首先,模拟数据:importpandas aspdimportnumpy asnpdf = pd.DataFrame({ 'order_no':[ 'order_18213', 'order_16061', ..._将年龄列的缺失值用平均值填充,将性别列中的男,女分别替换为0、1
文章浏览阅读293次。此篇由下边的对话引出。三疯:最近工作中有什么困扰吗?万人迷:有一件。最近同时进行的工作种类有点多,而且杂。经常在苦思冥想一个开发问题或者热火朝天写代码的时候,突然来了另一件事情,新来的事情还得马上处理。这种被随时打断的感觉挺痛苦的,还不得不在内心抗拒的情况下转而处理插入的紧急事情。三疯:嗯……我有个做法你可以借鉴下。深度思考时被打断确实挺痛苦程序员在思考一个问题的时候,会持续深入的想很多东西。我的..._代码 不能断点
文章浏览阅读545次。问题描述输出九九乘法表。 输出格式输出格式见下面的样例。乘号用“*”表示。 样例输出下面给出输出的前几行:11=121=2 22=431=3 32=6 33=941=4 42=8 43=12 44=16首先对问题进行分析,其实可以发现这就是一个简单的嵌套循环,顾名思义就是在循环中在循环一次。分析完毕代码如下:#include<stdio.h>int main() { int i, j; for (int i = 1; i < 10; i++) { _c语言for循环蓝桥杯
文章浏览阅读1.1w次,点赞5次,收藏11次。配置Minecraft服务端文件注:这是java版的服务端参数,参数介绍翻译自Mojang官方文档,地址:https://minecraft.gamepedia.com/Server.propertiesspawn-protection=16/* 通过将该值进行(x*2)+1的运算来决定出生点的保护半径。设置为0将不会禁用出生点保护。设置为0将会保护位于出生..._function-permission-level
文章浏览阅读750次。这里的Service指的是注册到容器中的一系列可以调用的类或方法(函数)。看下是如何做到的,以下只对开发composer扩展包进行说明,写在项目目录中的可以参考官方的说明。3.新建src目录,并添加具体的服务文件:Test.php。2.扩展包添加composer.json文件。1.新建一个扩展包。_tp6 composer 详解 csdn
文章浏览阅读2w次,点赞12次,收藏53次。TM1650使用经验TM1650芯片功能TM1650芯片引脚TM1650通讯协议TM1650使用电路TM1650底层编程向TM1650发送指令编程TM1650芯片功能TM1650 是一种带键盘扫描接口的 LED(发光二极管显示器)驱动控制专用电路。内部集成有 MCU输入输出控制数字接口、数据锁存器、LED 驱动、键盘扫描、辉度调节等电路。TM1650 性能稳定、质量可靠、抗干扰能力强,可适用于..._tm1650应用电路图
文章浏览阅读3.6k次,点赞2次,收藏8次。1、多个属性值的设置语句match (m:公司{名称:["test3","test2"]}) return m2、多个属性的查询以及merge的使用OPTIONAL MATCH (n:公司) where "test3" in n.名称 WITH nwhere n is null merge (m:公司{名称:["test3","test2"]})return m(1)判断属性是否存在:直接用 "属性值 in 节点.属性名"的形式(2)merge和where不可以同时使用,._neo4j 数组properties
文章浏览阅读3.6k次。lxml.etree._ElementUnicodeResult 转为字符在爬虫过程中,使用的是lxml的xpath查找对应的字段。address=each.xpath('.//address/text()')[0].strip()结果用address与一般的字符进行拼接时,总是出现UnicodeDecodeError: 'ascii' codec can't decode by..._lxml.etree._elementunicoderesult