容器化 nfs 服务器安装

这篇文章记录如何安装和使用容器化的nfs,目前只是临时使用验证某个服务,只记录安装使用过程,不做过多描述。

什么是 nfs

它的主要功能是通过网络让不同的机器系统之间可以彼此共享文件和目录。

NFS服务器可以允许NFS客户端将远端NFS服务器端的共享目录挂载到本地的NFS客户端中。一般用来存储共享视频,图片等静态数据。

安装

  1. 加载内核模块 nfs

    modprobe nfs
    modprobe nfsd
    
  2. 安装nfs-utils

    apt-get install nfs-common
    # 或者
    yum install nfs-utils
    
  3. 安装docker

    curl -sSL https://get.docker.com/ | sh
    usermod -aG docker $USER
    systemctl enable docker
    systemctl start docker
    
  4. 准备nfs配置文件

    例如:配置文件位于 ./exports.txt

    /nfs        *(rw,fsid=0,sync,no_root_squash)
    
  5. 运行服务器

    参考ehough/docker-nfs-server - github

    version: '3.2'
       
    services:
      nfs:
        image: erichough/nfs-server:latest
        container_name: nfs
        network_mode: bridge
        restart: always
        volumes:
          - /home/kelu/Workspace:/nfs
          - ./exports.txt:/etc/exports
        ports:
          - 2049:2049
          - 2049:2049/udp
          - 32765:32765
          - 32765:32765/udp
          - 32767:32767
          - 32767:32767/udp
        cap_add:
          -  SYS_ADMIN
        privileged: true
    

    将主机/home/kelu/Workspace 文件夹作为共享根目录。

  6. 客户端连接

    服务器ip为 172.10.1.100 ,将共享目录挂载到客户端的 /kelu 目录下

    mount -o nfsvers=4 172.10.1.100:/ /kelu
    mount # 查看挂载
    umount -v /kelu   # 解除挂载
    umount -f -l /app/Downloads # 服务端挂了的情况下接触挂载
    

错误参考

无法启动,显示“rpc.statd already running”

==================================================================
      STARTING SERVICES ...
==================================================================
----> starting rpcbind
----> starting exportfs
exportfs: /etc/exports [1]: Neither 'subtree_check' or 'no_subtree_check' specified for export "*:/nfs".
  Assuming default behaviour ('no_subtree_check').
  NOTE: this default has changed since nfs-utils version 1.0.x

----> starting rpc.mountd on port 32767
----> starting rpc.statd on port 32765 (outgoing from port 32766)
Statd service already running!
---->
----> ERROR: /sbin/rpc.statd failed
---->

先stop掉这个服务即可:

systemctl stop rpc-statd.service

参考资料


kubernetes kubectl 命令行

本文记录常用的kubectl命令行。

官方参考手册:https://kubernetes.io/docs/reference/

蚂蚁金服的 Jimmy Song(宋净超) 主导了一个Kubernetes Handbook 的开源项目,里面有官方手册中这一部分的中文参考,对英文苦手的可以看看:https://jimmysong.io/kubernetes-handbook/guide/command-usage.html

在此之前我们可以先看看命令行的帮助:

kubectl help

从帮助给我们划分了几个 kubectl 的命令主题:

  • 入门命令
  • 部署命令 deployment
  • 集群管理命令 cluster
  • 问题定位命令
  • 高级命令
  • 设置命令
  • 其它

下文的分类是我自己分配的,不按照帮助的显示顺序。

自动补全

$ source <(kubectl completion bash) # setup autocomplete in bash, bash-completion package should be installed first.
$ source <(kubectl completion zsh)  # setup autocomplete in zsh

或者永久性设置(bash):
kubectl completion bash >> ~/.bashrc
source ~/.bashrc

(zsh):
plugins=(kubectl)
source <(kubectl completion zsh)

帮助命令

$ kubectl help
$ kubectl explain pods,svc                       # get the documentation for pod and svc manifests

入门命令

  1. kubectl create

    kubectl run

    也可以用 kubectl apply

    $ kubectl create -f ./my-manifest.yaml           # create resource(s)
    $ kubectl create -f ./my1.yaml -f ./my2.yaml     # create from multiple files
    $ kubectl create -f ./dir                        # create resource(s) in all manifest files in dir
    $ kubectl create -f https://git.io/vPieo         # create resource(s) from url
    
    $ kubectl run nginx --image=nginx                # start a single instance of nginx
    
  2. $ kubectl delete -f ./pod.json                                              # Delete a pod using the type and name specified in pod.json
    $ kubectl delete pod,service baz foo                                        # Delete pods and services with same names "baz" and "foo"
    $ kubectl delete pods,services -l name=myLabel                              # Delete pods and services with label name=myLabel
    $ kubectl delete pods,services -l name=myLabel --include-uninitialized      # Delete pods and services, including uninitialized ones, with label name=myLabel
    $ kubectl -n default delete pv --all                                      # 删除 default 下所有的pv
    $ kubectl delete node xxx                                                 # 删除 node
    
  3. kubectl get xxx

    kubectl describe nodes xxx

    # 查询资源
    $ kubectl get services                          # List all services in the namespace
    $ kubectl get pods --all-namespaces             # List all pods in all namespaces
    $ kubectl get pods -o wide                      # List all pods in the namespace, with more details
    $ kubectl get deployment my-dep                 # List a particular deployment
    $ kubectl get pods --include-uninitialized      # List all pods in the namespace, including uninitialized ones
    
    # 资源详细描述
    $ kubectl describe nodes my-node
    $ kubectl describe pods my-pod
    
    # 排序
    $ kubectl get services --sort-by=.metadata.name
    $ kubectl get pods --sort-by='.status.containerStatuses[0].restartCount'
    
    # 选择标签
    $ kubectl get pods --selector=app=cassandra rc -o \
      jsonpath='{.items[*].metadata.labels.version}'
    $ kubectl get pods --field-selector=status.phase=Running
    
    # ExternalIPs
    $ kubectl get nodes -o jsonpath='{.items[*].status.addresses[?(@.type=="ExternalIP")].address}'
    
    # 列出所有密钥
    $ kubectl get pods -o json | jq '.items[].spec.containers[].env[]?.valueFrom.secretKeyRef.name' | grep -v null | sort | uniq
    
    # 列出事件按时间排序
    $ kubectl get events --sort-by=.metadata.creationTimestamp
    
  4. 用于更新 API 对象的命令有:

    kubectl patch,

    kubectl annotate,

    kubectl edit,

    kubectl replace,

    kubectl scale,

    kubectl apply,

    kubectl expose

    • 更改pod

      # 从json文件滚动升级pods的镜像
      $ kubectl rolling-update frontend-v1 -f frontend-v2.json       
      
      # 重命名 + 升级pod镜像
      $ kubectl rolling-update frontend-v1 frontend-v2 --image=image:v2  
      
      # 回滚pod
      $ kubectl rolling-update frontend-v1 frontend-v2 --rollback
      
      # 从json文件替换pod
      $ cat pod.json | kubectl replace -f - 
      
      # 强制替换pod
      $ kubectl replace --force -f ./pod.json
      
      # 暴露端口
      $ kubectl expose rc nginx --port=80 --target-port=8000
      
      # 更新pod镜像
      $ kubectl get pod mypod -o yaml | sed 's/\(image: myimage\):.*$/\1:v4/' | kubectl replace -f -
      
      $ kubectl label pods my-pod new-label=awesome                      # Add a Label
      $ kubectl annotate pods my-pod icon-url=http://goo.gl/XXBTWq       # Add an annotation
      $ kubectl autoscale deployment foo --min=2 --max=10                # Auto scale a deployment "foo"
      
      $ kubectl edit svc/docker-registry                      # Edit the service named docker-registry
      $ KUBE_EDITOR="nano" kubectl edit svc/docker-registry   # Use an alternative editor
      
    • patch 补丁

      kubectl patch 命令接受 YAML 或 JSON 格式的补丁,且补丁能够以文件或直接以命令行参数的形式进行传递

      kubectl patch 命令拥有一个 type 参数,可以将其设置为以下值:

      参数值 合并类型
      json JSON 补丁, RFC 6902
      merge JSON 合并补丁, RFC 7386
      strategic 默认值,策略性合并补丁

      使用JSON 合并补丁更新一个列表,必须重新定义整个列表。新的列表会完全替换掉原先的列表。

      # 策略性合并补丁
      $ kubectl patch node k8s-node-1 -p '{"spec":{"unschedulable":true}}' 
      $ kubectl patch deployment patch-demo --patch "$(cat patch-file.yaml)"
      $ kubectl patch pod valid-pod -p '{"spec":{"containers":[{"name":"kubernetes-serve-hostname","image":"new image"}]}}'
      
      # 查看补丁情况
      # kubectl get deployment patch-demo --output yaml
      
      $ kubectl patch pod valid-pod --type='json' -p='[{"op": "replace", "path": "/spec/containers/0/image", "value":"new image"}]'
      $ kubectl patch deployment valid-deployment  --type json   -p='[{"op": "remove", "path": "/spec/template/spec/containers/0/livenessProbe"}]'
      
      # 增加新值
      $ kubectl patch sa default --type='json' -p='[{"op": "add", "path": "/secrets/1", "value": {"name": "whatever" } }]'
      
    • scale

      $ kubectl scale --replicas=3 rs/foo                                 # Scale a replicaset named 'foo' to 3
      $ kubectl scale --replicas=3 -f foo.yaml                            # Scale a resource specified in "foo.yaml" to 3
      $ kubectl scale --current-replicas=2 --replicas=3 deployment/mysql  # If the deployment named mysql's current size is 2, scale mysql to 3
      $ kubectl scale --replicas=5 rc/foo rc/bar rc/baz                   # Scale multiple replication controllers
      
      
  5. 资源类型

    资源类型 简写
    all  
    certificatesigningrequests csr
    clusterrolebindings  
    clusterroles  
    componentstatuses cs
    configmaps cm
    controllerrevisions  
    cronjobs  
    customresourcedefinition crd, crds
    daemonsets ds
    deployments deploy
    endpoints ep
    events ev
    horizontalpodautoscalers hpa
    ingresses ing
    jobs  
    limitranges limits
    namespaces ns
    networkpolicies netpol
    nodes no
    persistentvolumeclaims pvc
    persistentvolumes pv
    poddisruptionbudgets pdb
    podpreset  
    pods po
    podsecuritypolicies psp
    podtemplates  
    replicasets rs
    replicationcontrollers rc
    resourcequotas quota
    rolebindings  
    roles  
    secrets  
    serviceaccount sa
    services svc
    statefulsets sts
    storageclasses sc
  6. 输出格式

    -o 或者 -output 标签

Output format Description
-o=custom-columns=<spec> Print a table using a comma separated list of custom columns
-o=custom-columns-file=<filename> Print a table using the custom columns template in the <filename> file
-o=json Output a JSON formatted API object
-o=jsonpath=<template> Print the fields defined in a jsonpath expression
-o=jsonpath-file=<filename> Print the fields defined by the jsonpath expression in the <filename> file
-o=name Print only the resource name and nothing else
-o=wide Output in the plain-text format with any additional information, and for pods, the node name is included
-o=yaml Output a YAML formatted API object
  1. 输出debug级别

    -v 或者 --v 标志

级别 描述
--v=0 Generally useful for this to ALWAYS be visible to an operator.
--v=1 A reasonable default log level if you don’t want verbosity.
--v=2 Useful steady state information about the service and important log messages that may correlate to significant changes in the system. This is the recommended default log level for most systems.
--v=3 Extended information about changes.
--v=4 Debug level verbosity.
--v=6 Display requested resources.
--v=7 Display HTTP request headers.
--v=8 Display HTTP request contents.
--v=9 Display HTTP request contents without truncation of contents.

问题定位命令

  1. 集群信息

    $ kubectl cluster-info                                                  # 集群信息
    $ kubectl cluster-info dump                                             # 更详细的集群信息
    $ kubectl cluster-info dump --output-directory=/path/to/cluster-state   # 输出到文件
    
    $ kubectl config current-context
    
  2. top

    $ kubectl top pod POD_NAME --containers               # Show metrics for a given pod and its containers
    $ kubectl top node my-node                                              # Show metrics for a given node
    
  3. 维护模式

    $ kubectl cordon my-node                                                # 设置节点不可调度
    $ kubectl drain my-node                                                 # 将节点的pod 平滑 迁移到其他节点
    $ kubectl uncordon my-node                                              # 取消节点不可调度。
    
    # 参考 Kubernetes中的Taint和Toleration(污点和容忍): https://jimmysong.io/posts/kubernetes-taint-and-toleration/
    # Taint(污点)和 Toleration(容忍)可以作用于 node 和 pod 上,其目的是优化 pod 在集群间的调度,
    # 具有 taint 的 node 和 pod 是互斥关系,而具有节点亲和性关系的 node 和 pod 是相吸的。
    
    # 为 node1 设置 taint:
    kubectl taint nodes node1 key1=value1:NoSchedule
    kubectl taint nodes node1 key1=value1:NoExecute
    kubectl taint nodes node1 key2=value2:NoSchedule
    # 删除 taint:
    kubectl taint nodes node1 key1:NoSchedule-
    kubectl taint nodes node1 key1:NoExecute-
    kubectl taint nodes node1 key2:NoSchedule-
    
    # 为 pod 设置 toleration
    只要在 pod 的 spec 中设置 tolerations 字段即可,可以有多个 key:
    tolerations:
    - key: "key1"
      operator: "Equal"
      value: "value1"
      effect: "NoSchedule"
    - key: "key1"
      operator: "Equal"
      value: "value1"
      effect: "NoExecute"
    - key: "node.alpha.kubernetes.io/unreachable"
      operator: "Exists"
      effect: "NoExecute"
      tolerationSeconds: 6000
    value 的值可以为 NoSchedule、PreferNoSchedule 或 NoExecute。
    tolerationSeconds 是当 pod 需要被驱逐时,可以继续在 node 上运行的时间。
    
  4. Pods 互动

    kubectl logs

    kubectl attach

    kubectl exec

    $ kubectl logs my-pod                                 # dump pod logs (stdout)
    $ kubectl logs my-pod -c my-container                 # dump pod container logs (stdout, multi-container case)
    $ kubectl logs -f my-pod --namespace="xx"                             # stream pod logs (stdout)
    $ kubectl logs -f my-pod -c my-container              # stream pod container logs (stdout, multi-container case)
    $ kubectl run -i --tty busybox --image=busybox -- sh  # Run pod as interactive shell
    $ kubectl attach my-pod -i                            # Attach to Running Container
    
    $ kubectl exec my-pod -- ls /                         # Run command in existing pod (1 container case)
    $ kubectl exec my-pod -c my-container -- ls /         # Run command in existing pod (multi-container case)
    
    
  5. 暴露端口

    kubectl port-forward 暴露本地端口给pod

    kubectl proxy 使API server监听在本地端口

    $ kubectl port-forward my-pod 5000:6000               # Listen on port 5000 on the local machine and forward to port 6000 on my-pod
    
    $ kubectl proxy --address='0.0.0.0'  --accept-hosts='^*$'
    

kubernetes 的一些博客和资料收集

当作一个todolist吧,需要把下面的资料和博客都看一遍。

目前看的博文最多的是 cloudman6 和 jimmysong


kubernetes storage入门

这篇文章记录如何使用 kubernetes 的存储资源,包括volume、pv&pvc等。

一、Volume

Volume 的生命周期独立于容器,Pod 中的容器可能被销毁和重建,但 Volume 会被保留。

Volume 提供了对各种 backend 的抽象,容器在使用 Volume 读写数据的时候不需要关心数据到底是存放在本地节点的文件系统还是云硬盘上。对它来说,所有类型的 Volume 都只是一个目录。

1. emptyDir

最基础的 Volume 类型。

emptyDir Volume 的生命周期与 Pod 一致。对于容器来说是持久的,对于 Pod 则不是。当 Pod 从节点删除时,Volume 的内容也会被删除。但如果只是容器被销毁而 Pod 还在,则 Volume 不受影响。Pod 中的所有容器都可以共享 Volume,它们可以指定各自的 mount 路径。

根据这个特性,emptyDir 特别适合 Pod 中的容器需要临时共享存储空间的场景。

2. hostPath Volume

hostPath Volume 的作用是将 Docker Host 文件系统中已经存在的目录 mount 给 Pod 的容器。持久性比 emptyDir 强。不过一旦 Host 崩溃,hostPath 也就没法访问了。

hostPath Volume 实际上增加了 Pod 与节点的耦合,限制了 Pod 的使用。不过那些需要访问 Kubernetes 或 Docker 内部数据的应用则需要使用 hostPath。

比如 kube-apiserver 和 kube-controller-manager 就是这样的应用

kubectl edit --namespace=kube-system pod kube-apiserver-k8s-master

3. 外部 Storage Provider

如果 Kubernetes 部署在诸如 AWS、GCE、Azure 等公有云上,可以直接使用云硬盘作为 Volume,也可以使用主流的分布式存储,比如 Ceph、GlusterFS 等。

相对于 emptyDir 和 hostPath,这些 Volume 类型的最大特点就是不依赖 Kubernetes。Volume 的底层基础设施由独立的存储系统管理,与 Kubernetes 集群是分离的。数据被持久化后,即使整个 Kubernetes 崩溃也不会受损。

Volume 提供了非常好的数据持久化方案,不过在可管理性上还有不足。下面介绍的 PV & PVC 可以在更高层次上对存储进行管理。

二、PV & PVC

引自 cloudman6

Volume 提供了非常好的数据持久化方案,不过在可管理性上还有不足。

拿前面 AWS EBS 的例子来说,要使用 Volume,Pod 必须事先知道如下信息:

  1. 当前 Volume 来自 AWS EBS。
  2. EBS Volume 已经提前创建,并且知道确切的 volume-id。

Pod 通常是由应用的开发人员维护,而 Volume 则通常是由存储系统的管理员维护。开发人员要获得上面的信息:

  1. 要么询问管理员。
  2. 要么自己就是管理员。

这样就带来一个管理上的问题:应用开发人员和系统管理员的职责耦合在一起了。如果系统规模较小或者对于开发环境这样的情况还可以接受。但当集群规模变大,特别是对于生成环境,考虑到效率和安全性,这就成了必须要解决的问题。

Kubernetes 给出的解决方案是 PersistentVolume 和 PersistentVolumeClaim。

PersistentVolume (PV) 是外部存储系统中的一块存储空间,由管理员创建和维护。与 Volume 一样,PV 具有持久性,生命周期独立于 Pod。

PersistentVolumeClaim (PVC) 是对 PV 的申请 (Claim)。PVC 通常由普通用户创建和维护。需要为 Pod 分配存储资源时,用户可以创建一个 PVC,指明存储资源的容量大小和访问模式(比如只读)等信息,Kubernetes 会查找并提供满足条件的 PV。

有了 PersistentVolumeClaim,用户只需要告诉 Kubernetes 需要什么样的存储资源,而不必关心真正的空间从哪里分配,如何访问等底层细节信息。这些 Storage Provider 的底层信息交给管理员来处理,只有管理员才应该关心创建 PersistentVolume 的细节信息。

Kubernetes 支持多种类型的 PersistentVolume,比如 AWS EBS、Ceph、NFS 等,完整列表请参考 https://kubernetes.io/docs/concepts/storage/persistent-volumes/#types-of-persistent-volumes

1. 三个概念: pv ,storageclass, pvc

  • pv - 持久化卷, 支持本地存储和网络存储, 例如hostpath,ceph rbd, nfs等,只支持两个属性, capacity和accessModes。其中capacity只支持size的定义,不支持iops等参数的设定,accessModes有三种
    • ReadWriteOnce(被单个node读写)
    • ReadOnlyMany(被多个nodes读)
    • ReadWriteMany(被多个nodes读写)
  • storageclass-另外一种提供存储资源的方式, 提供更多的层级选型, 如iops等参数。 但是具体的参数与提供方是绑定的。 如aws和gce它们提供的storageclass的参数可选项是有不同的。
  • pvc - 对pv或者storageclass资源的请求, pvc 对 pv 类比于pod 对不同的cpu, mem的请求。

下文以nfs为例,安装方式可以查看关联文章

2. PV

apiVersion: v1
kind: PersistentVolume
metadata:
  name: mypv1
spec:
  capacity:
    storage: 20Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Recycle
  storageClassName: mysqlpv
  mountOptions:
    - hard
    - nfsvers=4
  nfs:
    path: /
    server: 172.10.1.100
    
kubectl apply -f mysql-pv.yml    
kubectl get pv

NAME      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM     STORAGECLASS   REASON    AGE
mysqlpv   20Gi       RWO            Recycle          Available             mysqlpv                  12m

3. pvc

apiVersion: v1
kind: Service
metadata:
  name: mysql
spec:
  ports:
  - port: 3306
  selector:
    app: mysql
  clusterIP: None
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pv-claim
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 6Gi
  storageClassName: mysqlpv
---
apiVersion: apps/v1beta2
kind: Deployment
metadata:
  name: mysql
spec:
  selector:
    matchLabels:
      app: mysql
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - image: mysql:5.6
        name: mysql
        env:
          # Use secret in real usage
        - name: MYSQL_ROOT_PASSWORD
          value: password
        ports:
        - containerPort: 3306
          name: mysql
        volumeMounts:
        - name: mysql-persistent-storage
          mountPath: /var/lib/mysql
      volumes:
      - name: mysql-persistent-storage
        persistentVolumeClaim:
          claimName: mysql-pv-claim
  
kubectl apply -f mysql-deployment.yml

检查PV和PVC的信息

kubectl get pv

NAME      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS    CLAIM                    STORAGECLASS   REASON    AGE
mysqlpv   20Gi       RWO            Recycle          Bound     default/mysql-pv-claim   mysqlpv                  14m

kubectl describe pvc mysql-pv-claim

新建一个pod进入MySQL实例

kubectl run -it --rm --image=mysql:5.6 --restart=Never mysql-client -- mysql -h mysql -ppassword

测试

mysql> create database test;
mysql> show databases;

此时可以在nfs的共享目录中发现相应的文件。

4. 修改pv回收策略

将 pv 的字段 persistentVolumeReclaimPolicy: Recycle 修改为 persistentVolumeReclaimPolicy: Retain 即可。删除pvc时将不会删除在pv上生成的数据。

kubectl apply -f mysql-pv.yml 

PV 还支持 Delete 的回收策略,会删除 PV 在 Storage Provider 上对应存储空间。NFS 的 PV 不支持 Delete,支持 Delete 的 Provider 有 AWS EBS、GCE PD、Azure Disk、OpenStack Cinder Volume 等。

5. 回收pv

kubectl delete -f mysql-deployment.yml

此时可以看到 PV 状态会一直处于 Released,不能被其他 PVC 申请。

为了重新使用存储资源,可以删除并重新创建 mypv1。删除操作只是删除了 PV 对象,存储空间中的数据并不会被删除。

三、 StorageClass

PV 的动态供给由 StorageClass 实现。可以将其理解为配置文件。

上面例子中,创建 PV然后通过 PVC 申请并在 Pod 中使用的方式叫做静态供给(Static Provision)。

与之对应的是动态供给(Dynamical Provision)—— 没有满足 PVC 条件的 PV,会动态创建 PV。

相比静态供给,动态供给不需要提前创建 PV,减少了管理员的工作量,效率高。

动态供给是通过 StorageClass 实现的,StorageClass 定义了如何创建 PV。

参考资料


kubernetes 安装入门(centos)

这篇文章记录如何使用 kubeadm 安装 kubernetes。

目前官方推荐使用这种方法安装上测试环境,暂时不建议上生产环境。

环境配置

  1. 安装docker

    curl -sSL https://get.docker.com/ | sh
    usermod -aG docker $USER
    systemctl enable docker
    systemctl start docker
    
  2. 关闭系统防火墙

    systemctl stop firewalld && systemctl disable firewalld
    
  3. 关闭SElinux

    $ setenforce 0 (临时关闭)
    $ vi /etc/selinux/config (长久关闭)
    SELINUX=disabled
    
  4. 关闭系统交换区(出于k8s的性能考虑)

    不关闭临时分区的话参考后文,k8s初始化时修改配置文件即可。

    (临时)
    $ swapoff -a && sysctl -w vm.swappiness=0
    
    (长久)
    $ swapoff -a && cat >> /etc/sysctl.conf << EOF 
    vm.swappiness=0
    EOF
    
    $ sysctl -p
    
  5. 配置系统内核参数使流过网桥的流量也进入iptables/netfilter框架中:

    $ cat >> /etc/sysctl.conf<< EOF
    net.ipv4.ip_forward= 1
    net.bridge.bridge-nf-call-ip6tables= 1
    net.bridge.bridge-nf-call-iptables= 1
    EOF
    
    $ sysctl -p
    
  6. 重启docker和daemon

    systemctl daemon-reload
    systemctl restart docker
    

安装

  1. 配置阿里K8S YUM源

     cat <<EOF > /etc/yum.repos.d/kubernetes.repo
     [kubernetes]
     name=Kubernetes
     baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
     enabled=1
     gpgcheck=0
     EOF
    
     yum -y install epel-release
     yum clean all
     yum makecache
    
  2. 安装kubeadm和相关工具包

    yum -y install kubelet kubeadm kubectl kubernetes-cni
    
  3. 修改 kubeadm.conf

    $ vi /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
    # 修改 "cgroup-driver"值 由systemd变为cgroupfs
    # 原因是 cgroup-driver参数要与docker的一致,否则就会出问题
    Environment="KUBELET_CGROUP_ARGS=--cgroup-driver=cgroupfs"
    
    # 第九行增加swap-on=false
    Environment="KUBELET_EXTRA_ARGS=--fail-swap-on=false"
    
  4. 启动Docker与kubelet服务

    systemctl enable docker && systemctl start docker
    systemctl enable kubelet && systemctl start kubelet
    
  5. 查看系统日志

    此时kubelet的服务运行状态是异常的,因为缺少主配置文件kubelet.conf。但可以暂不处理,因为在完成Master节点的初始化后才会生成这个配置文件。

    tail -f /var/log/messages
    
  6. kubeadm初始化master节点

    目前最新版是1.10,也可以不用这个配置。

    kubeadm init --kubernetes-version=v1.10.0 --pod-network-cidr=10.244.0.0/16 --ignore-preflight-errors Swap
    

    最后一段的输出信息,类似于

    kubeadm join ...
    

    需要保存一份,后续添加工作节点还要用到。

  7. 配置kubectl认证信息

    # 对于非root用户
    mkdir -p $HOME/.kube
    sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
    sudo chown $(id -u):$(id -g) $HOME/.kube/config
    
    # 对于root用户
    export KUBECONFIG=/etc/kubernetes/admin.conf
    也可以直接放到~/.bash_profile
    echo "export KUBECONFIG=/etc/kubernetes/admin.conf" >> /etc/bash_profile
    echo "export KUBECONFIG=/etc/kubernetes/admin.conf" >> /etc/bashrc
    
  8. 安装flannel网络

    mkdir -p /etc/cni/net.d/
    cat <<EOF> /etc/cni/net.d/10-flannel.conf
    {
    "name": "cbr0",
    "type": "flannel",
    "delegate": {
    "isDefaultGateway": true
    }
    }
    EOF
    
    mkdir /usr/share/oci-umount/oci-umount.d -p
    mkdir -p /run/flannel/
    
    cat <<EOF> /run/flannel/subnet.env
    FLANNEL_NETWORK=10.244.0.0/16
    FLANNEL_SUBNET=10.244.1.0/24
    FLANNEL_MTU=1450
    FLANNEL_IPMASQ=true
    EOF
    
    kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/v0.9.1/Documentation/kube-flannel.yml
    
  9. node加入集群(可选)

    将第6步中的最后那个命令在node节点上运行即可。如果需要可以在后边加上跳过swap检测。

    kubeadm join --token xxx --discovery-token-ca-cert-hash sha256:xxx 172.10.1.100:6443  --ignore-preflight-errors Swap
    
    kubeadm join 10.19.0.55:6443 --token yvcyj2.8sx9plzgg0x2pyui --discovery-token-ca-cert-hash sha256:39a0baf9d08046eecbd593049b4d71e47d47478c01b6761c911da9589aed1f73 --ignore-preflight-errors Swap
    

    如果忘记token,在master节点上运行:

    # 确认token是否有效
    kubeadm token list      
    
    kubeadm token create --print-join-command
    

    默认token的有效期为24小时,当过期之后,该token就不可用了。解决方法如下:

    # 重新生成新的token
    kubeadm token create
    kubeadm token list
    
    # 获取ca证书sha256编码hash值
    openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'
    
    # 节点加入集群
    kubeadm join --token xxx --discovery-token-ca-cert-hash sha256:xxx  172.10.1.100:6443  --ignore-preflight-errors Swap
    
    kubeadm join 10.19.0.55:6443 --token yvcyj2.8sx9plzgg0x2pyui --discovery-token-ca-cert-hash sha256:39a0baf9d08046eecbd593049b4d71e47d47478c01b6761c911da9589aed1f73 --ignore-preflight-errors Swap
    

    更新 2019年2月26日:

    对于添加节点,如果出现这样的错误提示: [ERROR CRI]: unable to check if the container runtime at "/var/run/dockershim.sock" is running: exit status 1

    有可能是crictl的原因,在节点上并不需要这个东西,删除即可:

    rm /usr/bin/crictl

  10. 将 master 设置为node(可选)

   kubectl taint nodes --all node-role.kubernetes.io/master-
  1. 验证

    # 查看节点状态
    kubectl get nodes
    # 查看pods状态
    kubectl get pods --all-namespaces
    # 查看K8S集群状态
    kubectl get cs
    
  2. 重新安装(可选)

    kubeadm reset
    
  3. 安装UI界面 dashboard

    在k8s中 dashboard可以有两种访问方式:kubeconfig(HTTPS)和token(http)。

    这里只介绍 Token 方式的访问。

    $ git clone https://github.com/gh-Devin/kubernetes-dashboard.git
    $ cd kubernetes-dashboard
    $ ls
    heapster-rbac.yaml  heapster.yaml  kubernetes-dashboard-admin.rbac.yaml  kubernetes-dashboard.yaml
    
    $ vi kubernetes-dashboard.yaml
    # 因为权限问题,要将serviceAccountName: kubernetes-dashboard
    # 改为serviceAccountName: kubernetes-dashboard-admin
    
    $ kubectl  -n kube-system create -f .
    

    查看pod,确定是否已正常running

    kubectl get svc,pod --all-namespaces | grep dashboard
    

简单使用

一些简单的命令行使用说明:

kubectl cluster-info  # 查看集群信息
kubectl get pods      # 查看当前的 Pod
kubectl get services  # 查看应用被映射到节点的哪个端口
kubectl get services,pods --all-namespaces # 查看所有namespaces的应用和pod

kubectl get deployment # 查看副本数
kubectl describe deployment
kubectl get replicaset
kubectl describe replicaset

简单的创建资源:

  1. 用 kubectl 命令直接创建

    # 通过 kubectl 创建 Deployment。
    # Deployment 创建 ReplicaSet。
    # ReplicaSet 创建 Pod。
    kubectl run nginx-deployment --image=nginx:1.7.9 --replicas=2
    
    kubectl run kubernetes-bootcamp \
          --image=docker.io/jocatalin/kubernetes-bootcamp:v1 \
          --port=8080
    
  2. 用yml配置文件创建

    kubectl apply 不但能够创建 Kubernetes 资源,也能对资源进行更新,非常方便。

    不过 Kubernets 还提供了几个类似的命令,例如 kubectl createkubectl replacekubectl editkubectl patch

    kubectl apply -f nginx.yml
    
  3. 更新配置

    # 将8080端口映射到主机的随机端口
    kubectl expose deployment/kubernetes-bootcamp \
          --type="NodePort" \
          --port 8080
             
    
    # 更新副本数
    kubectl scale deployments/kubernetes-bootcamp --replicas=3      
    
    # 滚动更新
    kubectl set image deployments/kubernetes-bootcamp kubernetes-bootcamp=jocatalin/kubernetes-bootcamp:v2
    
    # 回退
    kubectl set image deployments/kubernetes-bootcamp kubernetes-bootcamp=jocatalin/kubernetes-bootcamp:v2
    
    # 删除
    kubectl delete pvc mypvc1 --force
    kubectl delete pv mypv1 --force
    
    

    参考资料


CentOS 7 使用代理服务器

这篇文章记录如何在 CentOS 7 下使用代理服务器,以此在国内服务器下载 k8s 的镜像,例如<k8s.gcr.io/defaultbackend:1.3>

代理客户端

代理客户端用来连接本地与服务器。

  1. 安装

    sudo yum -y install epel-release
    sudo yum -y install python-pip
    sudo pip install shadowsocks
    
  2. 配置

    sudo mkdir -p /etc/shadowsocks
    sudo vi /etc/shadowsocks/shadowsocks.json
    

    配置信息如下:

    {
        "server":"x.x.x.x",  # 服务器地址
        "server_port":1035,  # 服务器端口
        "local_address": "127.0.0.1", # 本地IP
        "local_port":1080,  # 本地端口
        "password":"password", # 连接密码
        "timeout":300,  # 等待超时时间
        "method":"aes-256-cfb",  # 加密方式
        "fast_open": false,  # true或false。开启fast_open以降低延迟,但要求Linux内核在3.7+
        "workers": 1  #工作线程数 
    }
    
  3. 自启动

    新建脚本

    touch /etc/systemd/system/shadowsocks.service
    # vi /etc/systemd/system/shadowsocks.service
    
    [Unit]
    Description=Shadowsocks
    [Service]
    TimeoutStartSec=0
    ExecStart=/usr/bin/sslocal -c /etc/shadowsocks/shadowsocks.json
    [Install]
    WantedBy=multi-user.target
    
  4. 启动Shadowsocks

    systemctl enable shadowsocks.service
    systemctl start shadowsocks.service
    systemctl status shadowsocks.service
    
  5. 验证运行状况

    curl --socks5 127.0.0.1:1080 -i http://ip.cn
    

    将会显示ip的具体位置。

privoxy

许多应用没有 socks 的能力。privoxy 用来将 socks5 代理转为 http 代理,就可以给大部分应用提供代理支持了。

  1. 安装

    yum install privoxy -y
    systemctl enable privoxy
    systemctl start privoxy
    systemctl status privoxy
    
  2. 配置

    cat >> /etc/privoxy/config << EOF
    forward-socks5t / 127.0.0.1:1080 .
    EOF
    
  3. 设置http、https代理

    # vi ~/.bashrc 在最后添加如下信息
    PROXY_HOST=127.0.0.1
    export all_proxy=http://$PROXY_HOST:8118
    export ftp_proxy=http://$PROXY_HOST:8118
    export http_proxy=http://$PROXY_HOST:8118
    export https_proxy=http://$PROXY_HOST:8118
    export no_proxy=localhost,172.16.0.0/16,192.168.0.0/16.,127.0.0.1,10.10.0.0/16
    
    # 重载环境变量
    source ~/.bashrc
    
  4. 验证运行状况

    curl -i http://ip.cn
    

    将会显示ip的具体位置。

取消代理,只要将 ~/.bashrc 中的内容取消掉,再 source 加载就好了。

参考资料