k8s六

2023-11-15

参考资料:从Docker到Kubernetes进阶-阳明

一、StatefulSet的设计原理

首先我们先来了解下Kubernetes的一个概念:有状态服务与无状态服务。

  • 无状态服务(Stateless Service):该服务运行的实例不会在本地存储需要持久化的数据,并且多个实例对于同一个请求响应的结果是完全一致的。这种方式适用于服务间相互没有依赖关系,如Web应用,在Deployment控制器停止掉其中的一个Pod不会对其他Pod造成影响。

  • 有状态服务(Stateful Service):服务运行的实例需要在本地存储持久化数据,比如数据库或者多个实例之间有依赖拓扑关系,比如:主从关系、主备关系。如果停止掉依赖中的一个Pod,就会导致数据丢失或者集群崩溃。这种实例之间有不对等关系,以及实例对外部数据有依赖关系的应用,就被称为“有状态应用”(Stateful Application)。

其中无状态服务在我们前面文章中使用的Deployment编排对象已经可以满足,因为无状态的应用不需要很多要求,只要保持服务正常运行就可以,Deployment删除掉任意中的Pod也不会影响服务的正常,但面对相对复杂的应用,比如有依赖关系或者需要存储数据,Deployment就无法满足条件了,Kubernetes项目也提供了另一个编排对象StatefulSet。

StatefulSet将有状态应用抽象为两种情况:

  1. 拓扑状态。这种情况意味着,应用的多个实例之间不是完全对等的关系。这些应用实例,必须按照某些顺序启动,比如应用的主节点 A 要先于从节点 B 启动。而如果你把 A 和 B 两个 Pod 删除掉,它们再次被创建出来时也必须严格按照这个顺序才行。并且,新创建出来的 Pod,必须和原来 Pod 的网络标识一样,这样原先的访问者才能使用同样的方法,访问到这个新 Pod。

  2. 存储状态。这种情况意味着,应用的多个实例分别绑定了不同的存储数据。对于这些应用实例来说,Pod A 第一次读取到的数据,和隔了十分钟之后再次读取到的数据,应该是同一份,哪怕在此期间 Pod A 被重新创建过。这种情况最典型的例子,就是一个数据库应用的多个存储实例。

StatefulSet 的核心功能,就是通过某种方式记录这些状态,然后在 Pod 被重新创建时,能够为新 Pod 恢复这些状态。它包含Deployment控制器ReplicaSet的所有功能,增加可以处理Pod的启动顺序,为保留每个Pod的状态设置唯一标识,同时具有以下功能:

  • 稳定的、唯一的网络标识符
  • 稳定的、持久化的存储
  • 有序的、优雅的部署和缩放

二、有状态服务的拓扑状态

在上面我们提到有状态应用大致抽象为拓扑状态和存储状态,拓扑状态是为应用多实例中有相互依赖的服务而实现的。首先我们先来了解StatefulSet如何保证唯一的网络标识,这就需要涉及到Kubernetes 项目中非常实用的概念:Headless Service

Service资源对象是k8s项目中用来将一组 Pod 暴露给外界访问的一种机制。

Service也分为两种方式分别是:

  • 第一种方式,是以 Service 的 VIP(Virtual IP,即:虚拟 IP)方式。比如:当我访问 10.0.23.1 这个 Service 的 IP 地址时,10.0.23.1 其实就是一个 VIP,它会把请求转发到该 Service 所代理的某一个 Pod 上,相当于前面的负载均衡代理。
  • 第二种方式,就是以 Service 的 DNS 方式。比如:这时候,只要我访问“my-svc.my-namespace.svc.cluster.local”这条 DNS 记录,就可以访问到名叫 my-svc 的 Service 所代理的某一个 Pod。

而第二种以DNS的方式又分为两种处理方法:

  • Normal Service:正常使用,访问“my-svc.my-namespace.svc.cluster.local”解析到的,正是 my-svc 这个 Service 的 VIP,然后将请求通过VIP地址转发到代理的Pod。
  • Headless Service:无头服务,访问“my-svc.my-namespace.svc.cluster.local”解析到的,直接就是 my-svc 代理的某一个 Pod 的 IP 地址。可以看到,这里的区别在于,Headless Service 不需要分配一个 VIP,而是可以直接以 DNS 记录的方式解析出被代理 Pod 的 IP 地址。

定义Headless Service 资源文件

apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None
  selector:
    app: nginx

Headless Service 在配置中和普通的Service的yaml文件定义基本相同,只是修改了clusterIP 字段为None,这样Headless Service 就不需要分配VIP地址,可以直接通过DNS的方式直接访问到Pod的IP地址。创建Headless Service 后它所代理的所有 Pod 的 IP 地址,都会被绑定一个这样格式的 DNS 记录:

<pod-name>.<svc-name>.<namespace>.svc.cluster.local

这个 DNS 记录,正是 Kubernetes 项目为 Pod 分配的唯一的“可解析身份”(Resolvable Identity)。有了这个“可解析身份”,只要你知道了一个 Pod 的名字,以及它对应的 Service 的名字,就可以通过这条 DNS 记录访问到 Pod 的 IP 地址。

定义StatefulSet资源文件

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  serviceName: "nginx"
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.9.1
        ports:
        - containerPort: 80
          name: web

上面这个YAML文件比我们之前部署的nginx-deployment增加了ServiceName:nginx的字段定义,即:告诉 StatefulSet 控制器,在执行控制循环(Control Loop)的时候,请使用 nginx 这个 Headless Service 来保证 Pod 的“可解析身份”。

下面我们创建这些资源:

$ kubectl create -f svc.yaml
$ kubectl get service nginx
NAME      TYPE         CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
nginx     ClusterIP    None         <none>        80/TCP    10s
$ kubectl create -f statefulset.yaml
$ kubectl get statefulset web
NAME      DESIRED   CURRENT   AGE
web       2         1         19s
$ kubectl get pods -l app=nginx
NAME    READY   STATUS    RESTARTS   AGE
web-0   1/1     Running   0          12m
web-1   1/1     Running   0          10m

可以看到,Pod的名字后面都以数字顺序为后缀,这个是因为StatefulSet 对它所管理 Pod 名字进行了编号,编号规则是:-,编号是从 0 开始累加,与 StatefulSet 的每个 Pod 实例一一对应,不会重复。这些 Pod 的创建,也是严格按照编号顺序进行的。比如,在 web-0 进入到 Running 状态、并且细分状态(Conditions)成为 Ready 之前,web-1 会一直处于 Pending 状态。

当这两个 Pod 都进入了 Running 状态之后,就可以查看到它们各自唯一的“网络身份”了。我们使用kubectl exec命令分别进入到容器中查看它们的 hostname。

$ kubectl exec web-0 -- sh -c 'hostname' 
web-0
$ kubectl exec web-1 -- sh -c 'hostname' 
web-1

然后我们启动一个一次性的pod来验证是否可以通过DNS解析到Pod的IP地址

$ kubectl run -i --tty --image busybox dns-test --restart=Never --rm /bin/sh
$ nslookup web-0.nginx
Server:    10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local

Name:      web-0.nginx
Address 1: 10.244.1.7

$ nslookup web-1.nginx
Server:    10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local

Name:      web-1.nginx
Address 1: 10.244.2.7

可以看到我们解析web-0.nginx这个DNS已经正确的返回了Pod的IP地址,现在我们再打开一个终端来删除这两个Pod,看看会发生什么样的变化?

$ kubectl delete pod -l app=nginx
pod "web-0" deleted
pod "web-1" deleted

查看Statefulset重新创建的Pod是否可以正常解析?

$ kubectl run -i --tty --image busybox dns-test --restart=Never --rm /bin/sh 
$ nslookup web-0.nginx
Server:    10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local

Name:      web-0.nginx
Address 1: 10.244.1.8

$ nslookup web-1.nginx
Server:    10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local

Name:      web-1.nginx
Address 1: 10.244.2.8

可以发现重新创建的pod也是按照原先的顺序来创建的,虽然Pod的IP地址有变化,但是用之前的DNS解析还是没有变化的,保持了原先的唯一网络标识,StatefulSet 也就保证了 Pod 网络标识的稳定性。至此Kubernetes 就成功地将 Pod 的拓扑状态(比如:哪个节点先启动,哪个节点后启动),按照 Pod 的“名字 + 编号”的方式固定了下来。

三、有状态服务的存储状态

下面我们来继续探究StatefulSet对存储状态的管理机制,在前面我们创建Pod需要使用存储的时候,只需要在资源文件中添加spec.volumes字段声明使用volume就可以,比如设置为hostpath或者emptyDir 。但实际环境中开发人员并不清楚我们那些Volume可以使用,所以存储我们就需要使用Kubernetes的另一个资源对象PVC(Persistent Volume Claim)的功能。

  • PVC 的全称是:PersistentVolumeClaim(持久化卷声明),PVC 是用户存储的一种声明,PVC 和 Pod 比较类似,Pod 消耗的是节点,PVC 消耗的是 PV 资源,Pod 可以请求 CPU 和内存,而 PVC 可以请求特定的存储空间和访问模式。对于真正使用存储的用户不需要关心底层的存储实现细节,只需要直接声明使用 PVC 即可,不会暴露后端存储的信息。
  • PV 的全称是:PersistentVolume(持久化卷),是对底层的共享存储的一种抽象,PV 由运维人员进行创建和配置,它和具体的底层的共享存储技术的实现方式有关,比如 Ceph、GlusterFS、NFS 等,都是通过插件机制完成与共享存储的对接。

PVC消耗的是PV资源,PV消耗的是后端共享存储。当我们创建一个PVC时,kubernetes 就会自动为PVC绑定一个符合条件的 PV,这里我们PV我们后续会在持久化存储文章中详细讲解,在这个例子中不做过多描述,这里我们已经提前创建完成。

继续以上面拓扑状态的应用为例,我们在资源文件中声明使用PVC:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  serviceName: "nginx"
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.9.1
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  - metadata:
      name: www
    spec:
      accessModes:
      - ReadWriteOnce  # Volume 的挂载方式是可读写,并且只能被挂载在一个节点上而非被多个节点共享。
      resources:
        requests:
          storage: 1Gi  #Volume 大小至少是 1 GiB。

我们为这个 StatefulSet 额外添加了一个volumeClaimTemplates字段。它跟 Deployment 里 Pod 模板(PodTemplate)的作用类似。也就是说,凡是被这个 StatefulSet 管理的 Pod,都会声明一个对应的 PVC;而这个 PVC 的定义,就来自于 volumeClaimTemplates这个模板字段。更重要的是,这个 PVC 的名字,会被分配一个与这个 Pod 完全一致的编号。其中这个自动创建的 PVC,与 PV 绑定成功后,就会进入 Bound 状态,这就意味着这个 Pod 可以挂载并使用这个 PV 了。

我们来创建这个资源对象:

$ kubectl create -f statefulset.yaml
$ kubectl get pvc -l app=nginx
NAME        STATUS    VOLUME                                     CAPACITY   ACCESSMODES   AGE
www-web-0   Bound     pvc-15c268c7-b507-11e6-932f-42010a800002   1Gi        RWO           48s
www-web-1   Bound     pvc-15c79307-b507-11e6-932f-42010a800002   1Gi        RWO           48s

可以看到PVC的命名方式为<PVC名字>-<StatefulSet名字>-<Pod编号>,PVC的状态已经显示为Bound,说明已经绑定到符合条件的PV,现在我们测试验证下数据是否会丢失 ?

分别往Pod的Volume目录中写入内容为hostname的index.html文件,然后分别访问pod的Nginx进程,查看返回信息是否正确

$ for i in 0 1; do kubectl exec web-$i -- sh -c 'echo hello $(hostname) > /usr/share/nginx/html/index.html'; done
$ for i in 0 1; do kubectl exec -it web-$i -- curl localhost; done
hello web-0
hello web-1

然后我们手动删除这两个Pod

$ kubectl delete pod -l app=nginx
pod "web-0" deleted
pod "web-1" deleted

被删除之后,这两个 Pod 会被按照编号的顺序被重新创建出来。然后我们在新创建的容器里通过访问“http://localhost”的方式去访问 web-0 里的 Nginx 服务:

# 在被重新创建出来的Pod容器里访问http://localhost
$ kubectl exec -it web-0 -- curl localhost
hello web-0

可以发现请求依然会返回:“hello web-0”,也就是说,原先与:“web-0” 的 Pod 绑定的 PV,在这个 Pod 被重新创建之后,依然和新的“ web-0 ” Pod 绑定在了一起。对于 Pod web-1 来说,也是完全一样的情况。

这是因为我们删除pod后,之前绑定的PV和PVC并不会删除,数据仍然保存在后端的远程存储如Ceph中,StatefulSet发现Pod消失后,会自动创建一个新的Pod,名字编号也是和之前相同,而这个新的Pod声明使用的还是之前的PVC名字,所以在这个新的 Pod 创建出来之后,Kubernetes 会为它查找之前绑定的PVC ,就会直接找到旧 Pod 遗留下来的同名的 PVC,进而找到跟这个 PVC 绑定在一起的 PV。这样新的 Pod 就可以挂载到旧 Pod 对应的那个 Volume,并且获取到保存在 Volume 里的数据。通过这种方式,Kubernetes 的 StatefulSet 就实现了对应用存储状态的管理。

四、使用StatefulSet控制器部署ES集群

1. 创建无头服务

编写elasticsearch-svc.yaml

kind: Service
apiVersion: v1
metadata:
  name: elasticsearch
  namespace: logging
  labels:
    app: elasticsearch
spec:
  selector:
    app: elasticsearch
  clusterIP: None
  ports:
    - port: 9200
      name: rest
    - port: 9300
      name: inter-node

创建服务资源对象

$ kubectl create -f elasticsearch-svc.yaml
$ kubectl  get svc -n logging
NAME            TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)             AGE
elasticsearch   ClusterIP   None            <none>        9200/TCP,9300/TCP   13d

2. 部署StorageClass持久化存储

集群使用NFS 作为后端存储资源,在主节点安装NFS,共享/data/k8s/目录。

$ systemctl stop firewalld.service
$ yum -y install nfs-utils rpcbind
$ mkdir -p /data/k8s
$ chmod 755 /data/k8s
$ vim /etc/exports
/data/k8s  *(rw,sync,no_root_squash)
$ systemctl start rpcbind.service
$ systemctl start nfs.service

创建nfs-client 的自动配置程序Provisioner, nfs-client.yaml

kind: Deployment
apiVersion: extensions/v1beta1
metadata:
  name: nfs-client-provisioner
spec:
  replicas: 1
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccountName: nfs-client-provisioner
      containers:
        - name: nfs-client-provisioner
          image: quay.io/external_storage/nfs-client-provisioner:latest
          volumeMounts:
            - name: nfs-client-root
              mountPath: /persistentvolumes
          env:
            - name: PROVISIONER_NAME
              value: fuseim.pri/ifs
            - name: NFS_SERVER
              value: 172.16.1.100
            - name: NFS_PATH
              value: /data/k8s
      volumes:
        - name: nfs-client-root
          nfs:
            server: 172.16.1.100
            path: /data/k8s

创建ServiceAccount,然后绑定集群对应的操作权限:nfs-client-sa.yaml

apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-client-provisioner

---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: nfs-client-provisioner-runner
rules:
  - apiGroups: [""]
    resources: ["persistentvolumes"]
    verbs: ["get", "list", "watch", "create", "delete"]
  - apiGroups: [""]
    resources: ["persistentvolumeclaims"]
    verbs: ["get", "list", "watch", "update"]
  - apiGroups: ["storage.k8s.io"]
    resources: ["storageclasses"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["events"]
    verbs: ["list", "watch", "create", "update", "patch"]
  - apiGroups: [""]
    resources: ["endpoints"]
    verbs: ["create", "delete", "get", "list", "watch", "patch", "update"]

---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: run-nfs-client-provisioner
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    namespace: default
roleRef:
  kind: ClusterRole
  name: nfs-client-provisioner-runner
  apiGroup: rbac.authorization.k8s.io

创建StorageClass,elasticsearch-storageclass.yaml

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: es-data-db
provisioner: fuseim.pri/ifs

部署服务资源对象

$ kubectl create -f nfs-client.yaml
$ kubectl create -f nfs-client-sa.yaml
$ kubectl create -f elasticsearch-storageclass.yaml 
$ kubectl  get pods 
NAME                                      READY   STATUS    RESTARTS   AGE
nfs-client-provisioner-5b486d9c65-9fzjz   1/1     Running   9          13d
$ kubectl get storageclass
NAME                PROVISIONER      AGE
es-data-db          fuseim.pri/ifs   13d

3. 使用StatefulSet 部署Es Pod

Elasticsearch 需要稳定的存储来保证 Pod 在重新调度或者重启后的数据依然不变,所以我们需要使用 StatefulSet 控制器来管理 Pod。

编写elasticsearch-statefulset.yaml

apiVersion: apps/v1
kind: StatefulSet    
metadata:
  name: es   #定义了名为 es 的 StatefulSet 对象
  namespace: logging
spec:
  serviceName: elasticsearch  #和前面创建的 Service 相关联,这可以确保使用以下 DNS 地址访问 StatefulSet 中的每一个 Pod:es-[0,1,2].elasticsearch.logging.svc.cluster.local,其中[0,1,2]对应于已分配的 Pod 序号。
  replicas: 3  #3个副本
  selector:    #设置匹配标签为app=elasticsearch
    matchLabels:
      app: elasticsearch    
  template:    #定义Pod模板
    metadata:
      labels: 
        app: elasticsearch
    spec: 
      initContainers:  #初始化容器,在主容器执行前运行
      - name: increase-vm-max-map  #第一个Init容器用来增加操作系统对mmap计数的限制
        image: busybox  
        command: ["sysctl", "-w", "vm.max_map_count=262144"]
        securityContext:
          privileged: true
      - name: increase-fd-ulimit   #第二个Init容器用来执行ulimit命令,增加打开文件描述符的最大数量
        image: busybox
        command: ["sh", "-c", "ulimit -n 65536"]
        securityContext:
          privileged: true
      containers:   
      - name: elasticsearch
        image: docker.elastic.co/elasticsearch/elasticsearch:7.6.2
        ports:
        - name: rest
          containerPort: 9200
        - name: inter
          containerPort: 9300
        resources:
          limits:
            cpu: 1000m
          requests:
            cpu: 1000m
        volumeMounts:
        - name: data
          mountPath: /usr/share/elasticsearch/data
        env: #声明变量
        - name: cluster.name  # #Elasticsearch 集群的名称
          value: k8s-logs  
        - name: node.name #节点的名称,
          valueFrom: 
            fieldRef:
              fieldPath: metadata.name
        - name: cluster.initial_master_nodes
          value: "es-0,es-1,es-2"
        - name: discovery.zen.minimum_master_nodes   #将其设置为(N/2) + 1,N是我们的群集中符合主节点的节点的数量。我们有3个 Elasticsearch 节点,因此我们将此值设置为2(向下舍入到最接近的整数)。
          value: "2"
        - name: discovery.seed_hosts #设置在 Elasticsearch 集群中节点相互连接的发现方法。
          value: "elasticsearch"
        - name: ES_JAVA_OPTS  #设置为-Xms512m -Xmx512m,告诉JVM使用512 MB的最小和最大堆。您应该根据群集的资源可用性和需求调整这些参数。
          value: "-Xms512m -Xmx512m"
        - name: network.host
          value: "0.0.0.0"
  volumeClaimTemplates:   #持久化模板
  - metadata:
      name: data 
      labels:
        app: elasticsearch
    spec:
      accessModes: [ "ReadWriteOnce" ] #只能被 mount 到单个节点上进行读写
      storageClassName:  es-data-db
      resources:
        requests:
          storage: 100Gi

创建服务资源对象

$ kubectl create -f elasticsearch-statefulset.yaml
statefulset.apps/es-cluster created
$ kubectl get pods -n logging
NAME                      READY     STATUS    RESTARTS   AGE
es-cluster-0              1/1       Running   0          20h
es-cluster-1              1/1       Running   0          20h
es-cluster-2              1/1       Running   0          20h

验证ES服务是否正常
将本地端口9200转发到 Elasticsearch 节点(如es-cluster-0)对应的端口:

$ kubectl port-forward es-cluster-0 9200:9200 --namespace=logging
Forwarding from 127.0.0.1:9200 -> 9200
Forwarding from [::1]:9200 -> 9200

打开另一个终端请求es,出现以下内容则为部署成功。

$ curl http://localhost:9200/_cluster/state?pretty

{
  "cluster_name" : "k8s-logs",
  "cluster_uuid" : "z9Hz1q9OS0G6GQBlWkOjuA",
  "version" : 19,
  "state_uuid" : "fjeJfNjjRkmFnX_1x_kzpg",
  "master_node" : "zcRrv4jnTfKFWGGdORpZKg",
  "blocks" : { },
  "nodes" : {
    "cqZH5iFOTYCKkNHiZK6uoQ" : {
      "name" : "es-0",
      "ephemeral_id" : "l3VAgaBYSLeY0wA9_CdWkw",
      "transport_address" : "192.168.85.195:9300",
      "attributes" : {
        "ml.machine_memory" : "8202764288",
        "ml.max_open_jobs" : "20",
        "xpack.installed" : "true"
      }
    },
    "zcRrv4jnTfKFWGGdORpZKg" : {
      "name" : "es-1",
      "ephemeral_id" : "LrD2UIReRfuIlGEArmwYuw",
      "transport_address" : "192.168.148.77:9300",
      "attributes" : {
        "ml.machine_memory" : "14543122432
-------

总结:

  1. StatefulSet 的控制器直接管理的是 Pod。通过在 Pod 的名字里加上事先约定好的编号,保证应用拓扑状态的服务稳定。
  2. Kubernetes 通过 Headless Service,为这些有编号的 Pod,在 DNS 服务器中生成带有同样编号的 DNS 记录,生成唯一的网络标识。
  3. StatefulSet 为每一个 Pod 分配并创建一个同样编号的 PVC。保证了每一个 Pod 都拥有一个独立的 Volume,保证数据不会丢失。

上篇文章:k8s五 | Pod的作业副本与滚动更新Deployment
系列文章:深入理解Kuerneters


关注公众号回复【k8s】关键词获取视频教程及更多资料:
前行技术圈

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

k8s六 的相关文章

  • Linux中的CONFIG_OF是什么?

    我看到它在很多地方被广泛使用 但不明白在什么场景下我需要使用它 What is 配置 OF OF 的全名是什么 打开固件 这是很久以前发明的 当时苹果公司正在生产基于 PowerPC CPU 的笔记本电脑 而 Sun Microsystem
  • 如何在 Kubernetes 中按特定顺序配置 Pod 初始化?

    我想知道如何按特定顺序开始部署 我知道initContainers但这对我不起作用 我有一个巨大的平台 有大约 20 个部署和 5 个有状态集 每个都有自己的服务 环境变量 卷 水平自动缩放器等 所以不可能 或者我不知道如何 在另一个中定义
  • 将主机中的空文件夹挂载到 Docker 中的非空文件夹

    我正在使用的工具是在 Docker 映像中提供的 由于安装该工具非常复杂 存在大量依赖项 因此我想使用 IDE 在主机上工作 但在容器上运行它 因此 下载并加载图像后 我运行 sudo docker run it v home myself
  • 如何将 kubectl 配置文件与 ~/.kube/config 合并?

    有没有一个简单的kubectl命令采取kubeconfig文件 包含 cluster context user 并将其合并到 kube config 文件作为附加上下文 Do this export KUBECONFIG kube conf
  • 无法从 jenkins 作为后台进程运行 nohup 命令

    更新 根据下面的讨论 我编辑了我的答案以获得更准确的描述 我正在尝试从詹金斯运行 nohup 命令 完整的命令是 nohup java jar home jar server process 0 35 jar prod gt gt var
  • Linux中的定时器类

    我需要一个计时器来以相对较低的分辨率执行回调 在 Linux 中实现此类 C 计时器类的最佳方法是什么 有我可以使用的库吗 如果您在框架 Glib Qt Wx 内编写 那么您已经拥有一个具有定时回调功能的事件循环 我认为情况并非如此 如果您
  • sendfile64 只复制约2GB

    我需要使用 sendfile64 复制大约 16GB 的文件 到目前为止我所取得的成就是 include
  • Kubernetes - 尝试部署时“安装卷失败”

    我部署了第一个容器 我得到了信息 deployment apps frontarena ads deployment created 但后来我看到我的容器创建陷入等待状态 然后我看到日志使用kubectl describe pod fron
  • 从镜像创建 Docker 容器而不启动它

    作为我的部署策略的一部分 我使用 Upstart 管理 Docker 容器 为此 我需要从注册表中提取图像并创建一个命名容器 如建议的那样 用于运行容器的新贵脚本不会管理生命周期 https stackoverflow com questi
  • 容器中的 JVM 计算处理器错误?

    最近我又做了一些研究 偶然发现了这一点 在向 OpenJDK 团队抱怨之前 我想看看是否有其他人观察到这一点 或者不同意我的结论 因此 众所周知 JVM 长期以来忽略了应用于 cgroup 的内存限制 众所周知 现在从 Java 8 更新某
  • 无法初始化 NVML:几个小时后 Docker 中出现未知错误

    我遇到有趣而奇怪的问题 当我使用 GPU 启动 docker 容器时 它工作正常 并且我看到 docker 中的所有 GPU 然而 几个小时或几天后 我无法在docker中使用GPU 当我做nvidia smi在泊坞窗机器中 我看到这条消息
  • Discord.net 无法在 Linux 上运行

    我正在尝试让在 Linux VPS 上运行的 Discord net 中编码的不和谐机器人 我通过单声道运行 但我不断收到此错误 Unhandled Exception System Exception Connection lost at
  • Docker 教程入门第 4 部分连接被拒绝

    我不明白我错过了什么 docker compose yml version 3 services web replace username repo tag with your name and image details image sv
  • docker 容器是否即时获取代码更改?

    我已经启动并运行了我的 docker 容器 有一个容器运行一些 python 代码 我发现它导致了一些错误 我想将一些代码行 主要是更多日志 添加到该特定容器内的 python 脚本中 我想进入容器docker exec ti contai
  • 如何在apache 2.4.6上安装apxs模块

    我刚刚用过apt get update我的 apache 已更新为2 4 6 我想安装 apxs 来编译模块 但收到此错误 The following packages have unmet dependencies apache2 pre
  • 如何管理AWS ECS中docker镜像的版本?

    AWS ECS 服务指向一个任务定义 其中包含 docker 镜像的名称 包括标签 因此 当我创建新版本的 docker 映像时 我有两种可能性 将任务定义更新到新版本 然后更新服务以指向任务定义的新版本 使用一些标签指向最后一个版本 假设
  • Linux:如何从特定端口发送TCP数据包?

    如何打开原始套接字以从特定 TCP 端口发送 我希望所有连接始终来自临时端口以下的一系列端口 如果您正在使用raw套接字 然后只需在数据包标头中填写正确的 TCP 源端口即可 相反 如果您使用 TCP 套接字接口 socket connec
  • 如何在shell中输出返回码?

    我正在尝试通过调用自定义 shell 脚本sh bin sh c myscript sh gt log txt 2 gt 1 echo 该命令的输出是创建的后台进程的 PID 我想指导 bin sh保存返回码myscript sh到某个文件
  • 如何将我的 pod 日志存储在持久存储中?

    我已经使用以下命令为我的 Pod 生成了日志kubectl logs pod name 但我想将这些日志保存在一个卷 某种持久存储 中 因为如果 Pod 宕机 容器日志将被清除 有没有办法做到这一点 我必须写某种脚本吗 我已经阅读了很多答案
  • ubuntu:升级软件(cmake)-版本消歧(本地编译)[关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 我的机器上安装了 cmake 2 8 0 来自 ubuntu 软件包 二进制文件放置在 usr bin cmake 中 我需要将 cmake 版本至少

随机推荐

  • 墨者学院-身份认证失效漏洞 解题思路

    题目要求 登陆马春生的账号 解题步骤 进去后首先看到提示 test test 登陆后 我们抓个包看看有没有啥信息 开启BP后我们直接在页面右键刷新刷新 好像没啥信息 点一下Forward 有了 20138880322 把末尾改个数字试一试
  • 微信小程序报错 Invalid attempt to destructure non-iterable instance.

    遇到的问题 TypeError Invalid attempt to destructure non iterable instance In order to be iterable non array objects must have
  • 腾讯/阿里/百度 BAT人才体系的职位层级、薪酬、晋升标准

    互联网圈有这么一句话 百度的技术 阿里的运营 腾讯的产品 那么代表互联网三座大山的BAT 内部人才体系有什么区别呢 今天智小培就带领大家看一看 腾讯 1 职级 腾讯职级体系分6级 最低1级 最高6级 同时按照岗位又划分为四大通道 内部也叫
  • 高等数值计算方法学习笔记第4章第二部分【数值积分(数值微分)】

    高等数值计算方法学习笔记第4章第二部分 数值积分 数值微分 四 龙贝格求积公式 第三次课 1 梯形法的递推化 变步长求积法 2 龙贝格算法 五 高斯求积公式 1 一般理论 1定义1例题 2 构造高斯求积公式方法 二 定理加证明 5 Gaus
  • 如何将.sql文件导入到mysql中

    第一 进入mysql数据库 在cmd中输入mysql u root p然后输入password 第二 新建一个数据库 可以与你想要导进来库的名字相同 create database test db 第三 进入所建立的空数据库test db
  • 现在的00后,真是卷死了呀,辞职信已经写好了·····

    都说00后躺平了 但是有一说一 该卷的还是卷 这不 三月份春招我们公司来了个00后 工作没两年 跳槽到我们公司起薪23K 都快接近我了 后来才知道人家是个卷王 从早干到晚就差搬张床到工位睡觉了 最近和他聊了一次天 原来这位小老弟家里条件不太
  • 排序算法(2)

    本文介绍插入排序和希尔排序 插入排序是较为常见的排序算法 希尔排序也是基础的排序算法 废话不多说 具体来看一下两种算法 插入排序 插入排序的基本思想是拿到下一个插入元素 在已经有序的待排数组部分找到自己的位置 然后进行数据的移动 完成该元素
  • Python每日一练第4天——合并两个有序数组

    合并两个有序数组 给你两个有序整数数组 nums1 和 nums2 请你将 nums2 合并到 nums1 中 使 nums1 成为一个有序数组 初始化 nums1 和 nums2 的元素数量分别为 m 和 n 你可以假设 nums1 的空
  • 浅谈深度学习的基础——神经网络算法(科普)

    浅谈深度学习的基础 神经网络算法 科普 神经网络算法是一门重要的机器学习技术 它是目前最为火热的研究方向 深度学习的基础 学习神经网络不仅可以让你掌握一门强大的机器学习方法 同时也可以更好地帮助你理解深度学习技术 人工神经网络早期的研究工作
  • 事务方法中保证数据只插入一次方案探究

    需求场景 在项目的接口请求中 我们有一个接口A需要事务支持 在接口A中调用了方法B 方法B也需要事务支持 两者都带有 Transactional注解 在B方法中是这个一个逻辑 查询本地数据库是否包含属性值为一个特定值的字段 如果没有的话就插
  • CodeBlocks中安装使用OpenCV3.4.14

    最近想在Windows下搭建OpenCV环境 看大部分都是采用VC进行搭建 考虑到VC环境太大 N多GB 所以选择小巧开源的CodeBlocks 参考网上的一些资料 在CodeBlocks 20 03中安装好了OpenCV3 4 14版本
  • 程序退出状态码

    状态码简介 上图是一个zsh的截图 当我们执行命令asdsad之后 因为没有这个命令 所以zsh 类似于bash的一种shell 输出没有找到这个命令 但是我们发现图中箭头 由绿色变成红色 表示程序不是正常退出 现在有一个问题是 zsh是怎
  • VS2008, MFC 文件的操作5 - 注册表 操作

    接上一节笔记 VS2008 MFC 文件的操作4 CFile类 CFileDialog类 方式 文本方式打开 1 在工程APP类 先在InitInstance中进行示范 不需要的特定初始化例程 更改用于存储设置的注册表项 TODO 应适当修
  • PostgreSQL 设置允许访问IP

    PostgreSQL安装后默认只能localhost 5432访问 检验方法 curl localhost 5432 访问成功提示 curl 52 Empty reply from server curl 127 0 0 1 5432 访问
  • Flutter

    前言 Image 是 Flutter 用于显示图像的小组件 它可以加载网络 本地 文件或者内存中的图像 支持 JPEG PNG GIF 动画 GIF WebP 动画 WebP BMP 和 WBMP 格式 Flutter Image 本身也实
  • springboot如何集成redis哨兵集群?

    前言 redis主从集群和redis sentinel集群都配置完毕了 现在我们需要了解spring boot 如何连接上该集群 才能用上这两个集群带来的便利 本章内容 为什么需要关注这个问题 怎么配置 记住 本章是针对redis已经配置了
  • Spark的新方案UnifiedMemoryManager内存管理模型分析

    StaticMemoryManager继承与MemoryManager 它是静态的内存分配 是1 6版本以前的实现 就像是建筑商建造好了房子 用户来到直接住进去就好了 弊端 有的人多住了小房子 有的人少住了大房子 而UnifiedMemor
  • neo4j下载安装配置步骤

    目录 一 介绍 简介 Neo4j和JDK版本对应 二 下载 官网下载 直接获取 三 解压缩安装 四 配置环境变量 五 启动测试 一 介绍 简介 Neo4j是一款高性能的图数据库 专门用于存储和处理图形数据 它采用节点 关系和属性的图形结构
  • linux安装服务器步骤,Linux服务器的安装配置流程

    不积跬步无以至千里 贴士 因为是装在Ubuntu系统上 其中有几个常用的命令告诉大家 下面在操作中你也会见到如下等命令 sudo gedit 文件目录对某个文件进行编辑和vi命令差不多 因为好多系统文件是只读的 可通过此方式来进行编辑修改
  • k8s六

    参考资料 从Docker到Kubernetes进阶 阳明 这里写目录标题 一 StatefulSet的设计原理 二 有状态服务的拓扑状态 三 有状态服务的存储状态 四 使用StatefulSet控制器部署ES集群 1 创建无头服务 2 部署