[root@k8s-master mainfests]# kubectl apply -f "https://cloud.weave.works/k8s/scope.yaml?k8s-version=$(kubectl version | base64 | tr -d '\n')" namespace/weave created #创建名称空间weave,也可以在创建时指定名称空间 serviceaccount/weave-scope created #创建serviceaccount clusterrole.rbac.authorization.k8s.io/weave-scope created clusterrolebinding.rbac.authorization.k8s.io/weave-scope created deployment.apps/weave-scope-app created #创建deployment service/weave-scope-app created #创建service daemonset.extensions/weave-scope-agent created #创建deamonset [root@k8s-master mainfests]# kubectl get ns NAME STATUS AGE default Active 68d ingress-nginx Active 28d kube-public Active 68d kube-system Active 68d weave Active 1m [root@k8s-master mainfests]# kubectl get deployment -n weave NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE weave-scope-app 1 1 1 1 1m [root@k8s-master mainfests]# kubectl get svc -n weave NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE weave-scope-app ClusterIP 10.97.229.215 <none> 80/TCP 33s [root@k8s-master mainfests]# kubectl get pod -n weave NAME READY STATUS RESTARTS AGE weave-scope-agent-5876w 1/1 Running 0 1m weave-scope-agent-d6jgt 1/1 Running 0 1m weave-scope-agent-t9p5g 1/1 Running 0 1m weave-scope-app-578556559-nfxrf 1/1 Running 0 1m
#创建Pod对象 [root@k8s-master ~]# kubectl apply -f require-nodeAffinity-pod.yaml pod/with-require-nodeaffinity created
#由于集群中并没有节点含有节点标签为zone=foo,所以创建的Pod一直处于Pending状态 [root@k8s-master ~]# kubectl get pods with-require-nodeaffinity NAME READY STATUS RESTARTS AGE with-require-nodeaffinity 0/1 Pending 0 35s
#查看Pending具体的原因 [root@k8s-master ~]# kubectl describe pods with-require-nodeaffinity ...... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning FailedScheduling 3s (x21 over 1m) default-scheduler 0/3 nodes are available: 3 node(s) didn't match node selector.
#给node01节点打上zone=foo的标签,可以看到成功调度到node01节点上 [root@k8s-master ~]# kubectl label node k8s-node01 zone=foo node/k8s-node01 labeled [root@k8s-master ~]# kubectl describe pods with-require-nodeaffinity Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning FailedScheduling 58s (x25 over 2m) default-scheduler 0/3 nodes are available: 3 node(s) didn't match node selector. Normal Pulled 4s kubelet, k8s-node01 Container image "ikubernetes/myapp:v1" already present on machine Normal Created 4s kubelet, k8s-node01 Created container Normal Started 4s kubelet, k8s-node01 Started container
[root@k8s-master ~]# kubectl get pods with-require-nodeaffinity -o wide NAME READY STATUS RESTARTS AGE IP NODE with-require-nodeaffinity 1/1 Running 0 6m 10.244.1.12 k8s-node01
[root@k8s-master ~]# kubectl run tomcat -l app=tomcat --image=tomcat:alpine deployment.apps/tomcat created [root@k8s-master ~]# kubectl get pods -l app=tomcat -o wide NAME READY STATUS RESTARTS AGE IP NODE tomcat-75fd5cc757-w9qdb 1/1 Running 0 5m 10.244.1.37 k8s-node01
#使用以下命令查看docker原生的三种网络 [root@localhost ~]# docker network ls NETWORK ID NAME DRIVER SCOPE 0efec019c899 bridge bridge local 40add8bb5f07 host host local ad94f0b1cca6 none null local
#none网络,在该网络下的容器仅有lo网卡,属于封闭式网络,通常用于对安全性要求较高并且不需要联网的应用 [root@localhost ~]# docker run -it --network=none busybox / # ifconfig lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 UP LOOPBACK RUNNING MTU:65536 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
#bridge网络,Docker安装完成时会创建一个名为docker0的linux bridge,不指定网络时,创建的网络默认为桥接网络,都会桥接到docker0上。 [root@localhost ~]# brctl show bridge name bridge id STP enabled interfaces docker0 8000.024229098fdd no
[root@localhost ~]# docker run -d nginx #运行一个nginx容器 c760a1b6c9891c02c992972d10a99639d4816c4160d633f1c5076292855bbf2b
[root@localhost ~]# brctl show bridge name bridge id STP enabled interfaces docker0 8000.024229098fdd no veth3f1b114
一个新的网络接口veth3f1b114桥接到了docker0上,veth3f1b114就是新创建的容器的虚拟网卡。进入容器查看其网络配置: [root@localhost ~]# docker exec -it c760a1b6c98 bash root@c760a1b6c989:/# apt-get update root@c760a1b6c989:/# apt-get iproute root@c760a1b6c989:/# ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever 38: eth0@if39: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0 valid_lft forever preferred_lft forever
VxLAN(Virtual extensible Local Area Network)虚拟可扩展局域网,采用MAC in UDP封装方式,具体的实现方式为:
1、将虚拟网络的数据帧添加到VxLAN首部,封装在物理网络的UDP报文中
2、以传统网络的通信方式传送该UDP报文
3、到达目的主机后,去掉物理网络报文的头部信息以及VxLAN首部,并交付给目的终端
跨节点的Pod之间的通信就是以上的一个过程,整个过程中通信双方对物理网络是没有感知的。如下网络图:
VxLAN的部署可以直接在官方上找到其YAML文件,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
[root@k8s-master:~# kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/bc79dd1505b0c8681ece4de4c0d86c5cd2643275/Documentation/kube-flannel.yml clusterrole.rbac.authorization.k8s.io/flannel created clusterrolebinding.rbac.authorization.k8s.io/flannel created serviceaccount/flannel created configmap/kube-flannel-cfg created daemonset.extensions/kube-flannel-ds-amd64 created daemonset.extensions/kube-flannel-ds-arm64 created daemonset.extensions/kube-flannel-ds-arm created daemonset.extensions/kube-flannel-ds-ppc64le created daemonset.extensions/kube-flannel-ds-s390x created
#输出如下结果表示flannel可以正常运行了 [root@k8s-master ~]# kubectl get daemonset -n kube-system NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE kube-flannel-ds 3 3 3 3 3 beta.kubernetes.io/arch=amd64 202d kube-proxy 3 3 3 3 3 beta.kubernetes.io/arch=amd64 202d
[root@k8s-master ~]# kubectl get node NAME STATUS ROLES AGE VERSION k8s-master Ready master 202d v1.11.2 k8s-node01 Ready <none> 202d v1.11.2 k8s-node02 Ready <none> 201d v1.11.2
[root@k8s-master ~]# kubectl apply -f kube-flannel.yml clusterrole.rbac.authorization.k8s.io/flannel configured clusterrolebinding.rbac.authorization.k8s.io/flannel configured serviceaccount/flannel unchanged configmap/kube-flannel-cfg configured daemonset.extensions/kube-flannel-ds-amd64 created daemonset.extensions/kube-flannel-ds-arm64 created daemonset.extensions/kube-flannel-ds-arm created daemonset.extensions/kube-flannel-ds-ppc64le created daemonset.extensions/kube-flannel-ds-s390x created
#查看路由信息 [root@k8s-master ~]# ip route ...... 10.244.1.0/24 via 192.168.56.12 dev eth0 10.244.2.0/24 via 192.168.56.13 dev eth0 ......
#查看路由表信息,可以看到其报文的发送方向都是和Directrouting是一样的 [root@k8s-master ~]# ip route ...... 10.244.1.0/24 via 192.168.56.12 dev eth0 10.244.2.0/24 via 192.168.56.13 dev eth0 .....
[root@k8s-master ~]# kubectl get ds canal -n kube-system NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE canal 3 3 0 3 0 beta.kubernetes.io/os=linux 2m
[root@k8s-master network-policy-demo]# kubectl get svc httpd-svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE httpd-svc NodePort 10.99.222.179 <none> 8080:30000/TCP 4m
[root@k8s-master network-policy-demo]# kubectl apply -f policy-demo.yaml networkpolicy.networking.k8s.io/deny-all-ingress created [root@k8s-master network-policy-demo]# kubectl get networkpolicy NAME POD-SELECTOR AGE deny-all-ingress <none> 11s
#此时再去访问测试,是无法ping通,无法访问的 [root@k8s-master ~]# kubectl run busybox --rm -it --image=busybox /bin/sh If you don't see a command prompt, try pressing enter. / # wget httpd-svc:8080 Connecting to httpd-svc:8080 (10.99.222.179:8080) wget: can't connect to remote host (10.99.222.179): Connection timed out
[root@k8s-master network-policy-demo]# kubectl apply -f policy-demo.yaml networkpolicy.networking.k8s.io/access-httpd created [root@k8s-master network-policy-demo]# kubectl get networkpolicy NAME POD-SELECTOR AGE access-httpd run=httpd 6s
验证NetworkPolicy的有效性:
1 2 3 4 5 6 7 8 9 10 11
#创建带有标签的busybox pod访问,是可以正常访问的,但是因为仅开放了TCP协议,所以PING是无法ping通的 [root@k8s-master ~]# kubectl run busybox --rm -it --labels="access=true" --image=busybox /bin/sh If you don't see a command prompt, try pressing enter. / # wget httpd-svc:8080 Connecting to httpd-svc:8080 (10.99.222.179:8080) index.html 100% |*********************************************************************************************| 45 0:00:00 ETA / # ping -c 3 10.244.0.2 PING 10.244.0.2 (10.244.0.2): 56 data bytes
#NetworkPolicy检测,一个带有access=true标签,一个不带 [root@k8s-master ~]# kubectl run busybox --rm -it --labels="access=true" --image=busybox /bin/sh If you don't see a command prompt, try pressing enter. / # wget httpd-svc:8080 Connecting to httpd-svc:8080 (10.99.222.179:8080) index.html 100% |*********************************************************************************************| 45 0:00:00 ETA / # exit Session ended, resume using 'kubectl attach busybox-686cb649b6-6j4qx -c busybox -i -t' command when the pod is running deployment.apps "busybox" deleted
[root@k8s-master ~]# kubectl run busybox2 --rm -it --image=busybox /bin/sh If you don't see a command prompt, try pressing enter. / # wget httpd-svc:8080 Connecting to httpd-svc:8080 (10.99.222.179:8080) wget: can't connect to remote host (10.99.222.179): Connection timed out
[root@k8s-master ~]# kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/master/src/deploy/recommended/kubernetes-dashboard.yaml secret/kubernetes-dashboard-certs created serviceaccount/kubernetes-dashboard created role.rbac.authorization.k8s.io/kubernetes-dashboard-minimal created rolebinding.rbac.authorization.k8s.io/kubernetes-dashboard-minimal created deployment.apps/kubernetes-dashboard created service/kubernetes-dashboard created
API Server作为Kubernetes网关,是访问和管理资源对象的唯一入口,其各种集群组件访问资源都需要经过网关才能进行正常访问和管理。每一次的访问请求都需要进行合法性的检验,其中包括身份验证、操作权限验证以及操作规范验证等,需要通过一系列验证通过之后才能访问或者存储数据到etcd当中。如下图:
一、ServiceAccount
Service account是为了方便Pod里面的进程调用Kubernetes API或其他外部服务而设计的。它与User account不同
User account是为人设计的,而service account则是为Pod中的进程调用Kubernetes API而设计;
User account是跨namespace的,而service account则是仅局限它所在的namespace;
从上面可以看到每个Pod无论定义与否都会有个存储卷,这个存储卷为default-token-*** token令牌,这就是pod和serviceaccount认证信息。通过secret进行定义,由于认证信息属于敏感信息,所以需要保存在secret资源当中,并以存储卷的方式挂载到Pod当中。从而让Pod内运行的应用通过对应的secret中的信息来连接apiserver,并完成认证。每个 namespace 中都有一个默认的叫做 default 的 service account 资源。进行查看名称空间内的secret,也可以看到对应的default-token。让当前名称空间中所有的pod在连接apiserver时可以使用的预制认证信息,从而保证pod之间的通信。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
[root@k8s-master ~]# kubectl get sa NAME SECRETS AGE default 1 50d [root@k8s-master ~]# kubectl get sa -n ingress-nginx #前期创建的ingress-nginx名称空间也存在这样的serviceaccount NAME SECRETS AGE default 1 11d nginx-ingress-serviceaccount 1 11d [root@k8s-master ~]# kubectl get secret NAME TYPE DATA AGE default-token-j5pf5 kubernetes.io/service-account-token 3 50d mysecret Opaque 2 1d tomcat-ingress-secret kubernetes.io/tls 2 10d [root@k8s-master ~]# kubectl get secret -n ingress-nginx NAME TYPE DATA AGE default-token-zl49j kubernetes.io/service-account-token 3 11d nginx-ingress-serviceaccount-token-mcsf4 kubernetes.io/service-account-token 3 11d
[root@k8s-master ~]# kubectl explain sa KIND: ServiceAccount VERSION: v1
DESCRIPTION: ServiceAccount binds together: * a name, understood by users, and perhaps by peripheral systems, for an identity * a principal that can be authenticated and authorized * a set of secrets
FIELDS: apiVersion <string> APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources
automountServiceAccountToken <boolean> AutomountServiceAccountToken indicates whether pods running as this service account should have an API token automatically mounted. Can be overridden at the pod level.
imagePullSecrets <[]Object> ImagePullSecrets is a list of references to secrets in the same namespace to use for pulling any images in pods that reference this ServiceAccount. ImagePullSecrets are distinct from Secrets because Secrets can be mounted in the pod, but ImagePullSecrets are only accessed by the kubelet. More info: https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod
kind <string> Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds
metadata <Object> Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata
secrets <[]Object> Secrets is the list of secrets allowed to be used by pods running using this ServiceAccount. More info: https://kubernetes.io/docs/concepts/configuration/secret
看到有一个 token 已经被自动创建,并被 service account 引用。设置非默认的 service account,只需要在 pod 的spec.serviceAccountName 字段中将name设置为您想要用的 service account 名字即可。在 pod 创建之初 service account 就必须已经存在,否则创建将被拒绝。需要注意的是不能更新已创建的 pod 的 service account。
[root@k8s-master pki]# kubectl config use-context magedu@kubernetes Switched to context "magedu@kubernetes". [root@k8s-master pki]# kubectl get pods No resources found. Error from server (Forbidden): pods is forbidden: User "magedu" cannot list pods in the namespace "default"
[root@k8s-master ~]# kubectl create role -h #查看角色创建帮助 Create a role with single rule.
Examples: # Create a Role named "pod-reader" that allows user to perform "get", "watch" and "list" on pods kubectl create role pod-reader --verb=get --verb=list --verb=watch --resource=pods # Create a Role named "pod-reader" with ResourceName specified kubectl create role pod-reader --verb=get --resource=pods --resource-name=readablepod --resource-name=anotherpod # Create a Role named "foo" with API Group specified kubectl create role foo --verb=get,list,watch --resource=rs.extensions # Create a Role named "foo" with SubResource specified kubectl create role foo --verb=get,list,watch --resource=pods,pods/status
Options: --allow-missing-template-keys=true: If true, ignore any errors in templates when a field or map key is missing in the template. Only applies to golang and jsonpath output formats. --dry-run=false: If true, only print the object that would be sent, without sending it. -o, --output='': Output format. One of: json|yaml|name|go-template|go-template-file|templatefile|template|jsonpath|jsonpath-file. --resource=[]: Resource that the rule applies to --resource-name=[]: Resource in the white list that the rule applies to, repeat this flag for multiple items --save-config=false: If true, the configuration of current object will be saved in its annotation. Otherwise, the annotation will be unchanged. This flag is useful when you want to perform kubectl apply on this object in the future. --template='': Template string or path to template file to use when -o=go-template, -o=go-template-file. The template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview]. --validate=true: If true, use a schema to validate the input before sending it --verb=[]: Verb that applies to the resources contained in the rule
Usage: kubectl create role NAME --verb=verb --resource=resource.group/subresource [--resource-name=resourcename] [--dry-run] [options] 使用kubectl create进行创建角色,指定角色名称,--verb指定权限,--resource指定资源或者资源组,--dry-run单跑模式并不会创建 Use "kubectl options" for a list of global command-line options (applies to all commands).
[root@k8s-master ~]# kubectl create rolebinding -h #角色绑定创建帮助 Create a RoleBinding for a particular Role or ClusterRole.
Examples: # Create a RoleBinding for user1, user2, and group1 using the admin ClusterRole kubectl create rolebinding admin --clusterrole=admin --user=user1 --user=user2 --group=group1
Options: --allow-missing-template-keys=true: If true, ignore any errors in templates when a field or map key is missing in the template. Only applies to golang and jsonpath output formats. --clusterrole='': ClusterRole this RoleBinding should reference --dry-run=false: If true, only print the object that would be sent, without sending it. --generator='rolebinding.rbac.authorization.k8s.io/v1alpha1': The name of the API generator to use. --group=[]: Groups to bind to the role -o, --output='': Output format. One of: json|yaml|name|templatefile|template|go-template|go-template-file|jsonpath-file|jsonpath. --role='': Role this RoleBinding should reference --save-config=false: If true, the configuration of current object will be saved in its annotation. Otherwise, the annotation will be unchanged. This flag is useful when you want to perform kubectl apply on this object in the future. --serviceaccount=[]: Service accounts to bind to the role, in the format <namespace>:<name> --template='': Template string or path to template file to use when -o=go-template, -o=go-template-file. The template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview]. --validate=true: If true, use a schema to validate the input before sending it
Usage: kubectl create rolebinding NAME --clusterrole=NAME|--role=NAME [--user=username] [--group=groupname] [--serviceaccount=namespace:serviceaccountname] [--dry-run] [options] 使用kubectl create进行创建角色绑定,指定角色绑定的名称,--role|--clusterrole指定绑定哪个角色,--user指定哪个用户 Use "kubectl options" for a list of global command-line options (applies to all commands).
[root@k8s-master mainfests]# kubectl get rolebinding #获取角色绑定信息 NAME AGE magedu-read-pods 1h [root@k8s-master mainfests]# kubectl delete rolebinding magedu-read-pods #删除前面的绑定 rolebinding.rbac.authorization.k8s.io "magedu-read-pods" deleted
[ik8s@k8s-master ~]$ kubectl get pods #删除后,在ik8s普通用户上进行获取pods资源信息,就立马出现forbidden了 No resources found. Error from server (Forbidden): pods is forbidden: User "magedu" cannot list pods in the namespace "default"
[root@k8s-master mainfests]# kubectl apply -f clusterrolebinding-demo.yaml clusterrolebinding.rbac.authorization.k8s.io/magedu-read-all-pods created [root@k8s-master mainfests]# kubectl get clusterrolebinding NAME AGE ...... magedu-read-all-pods 10s
[ik8s@k8s-master ~]$ kubectl get pods #角色绑定后在ik8s终端上进行获取pods信息,已经不会出现forbidden了 NAME READY STATUS RESTARTS AGE filebeat-ds-hxgdx 1/1 Running 1 36d filebeat-ds-s466l 1/1 Running 2 36d myapp-0 1/1 Running 0 2d myapp-1 1/1 Running 0 2d myapp-2 1/1 Running 0 2d myapp-3 1/1 Running 0 2d pod-sa-demo 1/1 Running 0 1d pod-vol-demo 2/2 Running 0 4d redis-5b5d6fbbbd-q8ppz 1/1 Running 1 4d [ik8s@k8s-master ~]$ kubectl get pods -n ingress-nginx #更换名称空间进行查看也是可行的 NAME READY STATUS RESTARTS AGE default-http-backend-7db7c45b69-nqxw9 1/1 Running 1 4d nginx-ingress-controller-6bd7c597cb-9fzbw 1/1 Running 0 4d
[ik8s@k8s-master ~]$ kubectl delete pods pod-sa-demo #但是进行删除pod就无法进行,因为在授权时是没有delete权限的 Error from server (Forbidden): pods "pod-sa-demo" is forbidden: User "magedu" cannot delete pods in the namespace "default"
在deployment中,每一个pod是没有名称,是随机字符串,是无序的。而statefulset中是要求有序的,每一个pod的名称必须是固定的。当节点挂了,重建之后的标识符是不变的,每一个节点的节点名称是不能改变的。pod名称是作为pod识别的唯一标识符,必须保证其标识符的稳定并且唯一。 为了实现标识符的稳定,这时候就需要一个headless service 解析直达到pod,还需要给pod配置一个唯一的名称。
DESCRIPTION: StatefulSet represents a set of pods with consistent identities. Identities are defined as: - Network: A single stable DNS and hostname. - Storage: As many VolumeClaims as requested. The StatefulSet guarantees that a given network identity will always map to the same storage identity.
[root@k8s-master ~]# cd mainfests/volumes [root@k8s-master volumes]# vim pv-demo.yaml [root@k8s-master volumes]# kubectl apply -f pv-demo.yaml persistentvolume/pv001 created persistentvolume/pv002 created persistentvolume/pv003 created persistentvolume/pv004 created persistentvolume/pv005 created [root@k8s-master volumes]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pv001 1Gi RWO,RWX Retain Available 5s pv002 2Gi RWO Retain Available 5s pv003 2Gi RWO,RWX Retain Available 5s pv004 2Gi RWO,RWX Retain Available 5s pv005 2Gi RWO,RWX Retain Available 5s
[root@k8s-master ~]# kubectl explain pods.spec.volumes.emptyDir #查看emptyDir存储定义 [root@k8s-master ~]# kubectl explain pods.spec.containers.volumeMounts #查看容器挂载方式 [root@k8s-master ~]# cd mainfests && mkdir volumes && cd volumes [root@k8s-master volumes]# cp ../pod-demo.yaml ./ [root@k8s-master volumes]# mv pod-demo.yaml pod-vol-demo.yaml [root@k8s-master volumes]# vim pod-vol-demo.yaml #创建emptyDir的清单 apiVersion: v1 kind: Pod metadata: name: pod-demo namespace: default labels: app: myapp tier: frontend annotations: magedu.com/create-by:"cluster admin" spec: containers: - name: myapp image: ikubernetes/myapp:v1 imagePullPolicy: IfNotPresent ports: - name: http containerPort: 80 volumeMounts: #在容器内定义挂载存储名称和挂载路径 - name: html mountPath: /usr/share/nginx/html/ - name: busybox image: busybox:latest imagePullPolicy: IfNotPresent volumeMounts: - name: html mountPath: /data/ #在容器内定义挂载存储名称和挂载路径 command: ['/bin/sh','-c','while true;do echo $(date) >> /data/index.html;sleep 2;done'] volumes: #定义存储卷 - name: html #定义存储卷名称 emptyDir: {} #定义存储卷类型 [root@k8s-master volumes]# kubectl apply -f pod-vol-demo.yaml pod/pod-vol-demo created [root@k8s-master volumes]# kubectl get pods NAME READY STATUS RESTARTS AGE pod-vol-demo 2/2 Running 0 27s [root@k8s-master volumes]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE ...... pod-vol-demo 2/2 Running 0 16s 10.244.2.34 k8s-node02 ......
在上面,我们定义了2个容器,其中一个容器是输入日期到index.html中,然后验证访问nginx的html是否可以获取日期。以验证两个容器之间挂载的emptyDir实现共享。如下访问验证: [root@k8s-master volumes]# curl 10.244.2.34 #访问验证 Tue Oct 9 03:56:53 UTC 2018 Tue Oct 9 03:56:55 UTC 2018 Tue Oct 9 03:56:57 UTC 2018 Tue Oct 9 03:56:59 UTC 2018 Tue Oct 9 03:57:01 UTC 2018 Tue Oct 9 03:57:03 UTC 2018 Tue Oct 9 03:57:05 UTC 2018 Tue Oct 9 03:57:07 UTC 2018 Tue Oct 9 03:57:09 UTC 2018 Tue Oct 9 03:57:11 UTC 2018 Tue Oct 9 03:57:13 UTC 2018 Tue Oct 9 03:57:15 UTC 2018
(1)查看hostPath存储类型定义 [root@k8s-master volumes]# kubectl explain pods.spec.volumes.hostPath KIND: Pod VERSION: v1
RESOURCE: hostPath <Object>
DESCRIPTION: HostPath represents a pre-existing file or directory on the host machine that is directly exposed to the container. This is generally used for system agents or other privileged things that are allowed to see the host machine. Most containers will NOT need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath
Represents a host path mapped into a pod. Host path volumes do not support ownership management or SELinux relabeling.
FIELDS: path <string> -required- #指定宿主机的路径 Path of the directory on the host. If the path is a symlink, it will follow the link to the real path. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath
type <string> Type for HostPath Volume Defaults to "" More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath
[root@k8s-master volumes]# kubectl explain pods.spec.volumes ...... configMap <Object> ConfigMap represents a configMap that should populate this volume
secret <Object> Secret represents a secret that should populate this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret
[root@k8s-master ~]# kubectl create secret -h Create a secret using specified subcommand.
Available Commands: docker-registry Create a secret for use with a Docker registry generic Create a secret from a local file, directory or literal value tls Create a TLS secret
Usage: kubectl create secret [flags] [options]
Use "kubectl <command> --help" for more information about a given command. Use "kubectl options" for a list of global command-line options (applies to all commands).
每个 --from-literal 对应一个信息条目。 [root@k8s-master ~]# kubectl create secret generic mysecret --from-literal=username=admin --from-literal=password=123456 secret/mysecret created [root@k8s-master ~]# kubectl get secret NAME TYPE DATA AGE mysecret Opaque 2 6s
2、通过 –from-file: 每个文件内容对应一个信息条目。
1 2 3 4 5 6 7
[root@k8s-master ~]# echo -n admin > ./username [root@k8s-master ~]# echo -n 123456 > ./password [root@k8s-master ~]# kubectl create secret generic mysecret --from-file=./username --from-file=./password secret/mysecret created [root@k8s-master ~]# kubectl get secret NAME TYPE DATA AGE mysecret Opaque 2 6s
[root@k8s-master volumes]# kubectl create configmap nginx-config --from-literal=nginx_port=80 --from-literal=server_name=myapp.magedu.com configmap/nginx-config created [root@k8s-master volumes]# kubectl get cm NAME DATA AGE nginx-config 2 6s [root@k8s-master volumes]# kubectl describe cm nginx-config Name: nginx-config Namespace: default Labels: <none> Annotations: <none>
Data ==== server_name: ---- myapp.magedu.com nginx_port: ---- 80 Events: <none>
Kubernetes 具有强大的副本控制能力,能保证在任意副本(Pod)挂掉时自动从其他机器启动一个新的,还可以动态扩容等,通俗地说,这个 Pod 可能在任何时刻出现在任何节点上,也可能在任何时刻死在任何节点上;那么自然随着 Pod 的创建和销毁,Pod IP 肯定会动态变化;那么如何把这个动态的 Pod IP 暴露出去?这里借助于 Kubernetes 的 Service 机制,Service 可以以标签的形式选定一组带有指定标签的 Pod,并监控和自动负载他们的 Pod IP,那么我们向外暴露只暴露 Service IP 就行了;这就是 NodePort 模式:即在每个节点上开起一个端口,然后转发到内部 Pod IP 上,如下图所示: 此时的访问方式:http://nodeip:nodeport/
2、端口管理问题
采用 NodePort 方式暴露服务面临问题是,服务一旦多起来,NodePort 在每个节点上开启的端口会及其庞大,而且难以维护;这时,我们可以能否使用一个Nginx直接对内进行转发呢?众所周知的是,Pod与Pod之间是可以互相通信的,而Pod是可以共享宿主机的网络名称空间的,也就是说当在共享网络名称空间时,Pod上所监听的就是Node上的端口。那么这又该如何实现呢?简单的实现就是使用 DaemonSet 在每个 Node 上监听 80,然后写好规则,因为 Nginx 外面绑定了宿主机 80 端口(就像 NodePort),本身又在集群内,那么向后直接转发到相应 Service IP 就行了,如下图所示:
DESCRIPTION: Ingress is a collection of rules that allow inbound connections to reach the endpoints defined by a backend. An Ingress can be configured to give services externally-reachable urls, load balance traffic, terminate SSL, offer name based virtual hosting etc.
FIELDS: apiVersion <string> APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources
kind <string> Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds
metadata <Object> Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata
spec <Object> Spec is the desired state of the Ingress. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status
status <Object> Status is the current state of the Ingress. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status
--- [root@k8s-master ingress-nginx]# kubectl apply -f namespace.yaml namespace/ingress-nginx created
(3)创建ingress controller的pod
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
[root@k8s-master ingress-nginx]# kubectl apply -f ./ configmap/nginx-configuration created deployment.extensions/default-http-backend created service/default-http-backend created namespace/ingress-nginx configured serviceaccount/nginx-ingress-serviceaccount created clusterrole.rbac.authorization.k8s.io/nginx-ingress-clusterrole created role.rbac.authorization.k8s.io/nginx-ingress-role created rolebinding.rbac.authorization.k8s.io/nginx-ingress-role-nisa-binding created clusterrolebinding.rbac.authorization.k8s.io/nginx-ingress-clusterrole-nisa-binding created configmap/tcp-services created configmap/udp-services created deployment.extensions/nginx-ingress-controller created [root@k8s-master ingress-nginx]# kubectl get pod -n ingress-nginx -w NAME READY STATUS RESTARTS AGE default-http-backend-7db7c45b69-gjrnl 0/1 ContainerCreating 0 35s nginx-ingress-controller-6bd7c597cb-6pchv 0/1 ContainerCreating 0 34s
[root@k8s-node01 ~]# docker pull mirrorgooglecontainers/defaultbackend-amd64:1.5 1.5: Pulling from mirrorgooglecontainers/defaultbackend-amd64 9ecb1e82bb4a: Pull complete Digest: sha256:d08e129315e2dd093abfc16283cee19eabc18ae6b7cb8c2e26cc26888c6fc56a Status: Downloaded newer image for mirrorgooglecontainers/defaultbackend-amd64:1.5
[root@k8s-node01 ~]# docker tag mirrorgooglecontainers/defaultbackend-amd64:1.5 k8s.gcr.io/defaultbackend-amd64:1.5 [root@k8s-node01 ~]# docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE mirrorgooglecontainers/defaultbackend-amd64 1.5 b5af743e5984 34 hours ago 5.13MB k8s.gcr.io/defaultbackend-amd64 1.5 b5af743e5984 34 hours ago 5.13MB
DESCRIPTION: Spec is the desired state of the Ingress. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status
IngressSpec describes the Ingress the user wishes to exist.
FIELDS: backend <Object> #定义后端有哪几个主机 A default backend capable of servicing requests that don't match any rule. At least one of 'backend' or 'rules' must be specified. This field is optional to allow the loadbalancer controller or defaulting logic to specify a global default.
rules <[]Object> #定义规则 A list of host rules used to configure the Ingress. If unspecified, or no rule matches, all traffic is sent to the default backend.
tls <[]Object> TLS configuration. Currently the Ingress only supports a single TLS port, 443. If multiple members of this list specify different hosts, they will be multiplexed on the same port according to the hostname specified through the SNI TLS extension, if the ingress controller fulfilling the ingress supports SNI.
kubernetes.io/ingress.class: nginx Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal CREATE 1m nginx-ingress-controller Ingress default/ingress-myapp
[root@k8s-master ingress]# kubectl get pods -n ingress-nginx NAME READY STATUS RESTARTS AGE default-http-backend-7db7c45b69-fndwp 1/1 Running 0 31m nginx-ingress-controller-6bd7c597cb-6pchv 1/1 Running 0 55m
[root@k8s-master ingress]# kubectl exec tomcat-deploy-6dd558cd64-b4xbm -- netstat -tnl Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 127.0.0.1:8005 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:8009 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:8080 0.0.0.0:* LISTEN
[root@k8s-master ingress]# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE ...... tomcat ClusterIP 10.104.158.148 <none> 8080/TCP,8009/TCP 28m
kubernetes.io/ingress.class: nginx Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal CREATE 2m nginx-ingress-controller Ingress default/tomcat
kubernetes.io/ingress.class: nginx Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal CREATE 20s nginx-ingress-controller Ingress default/ingress-tomcat-tls
DESCRIPTION: DEPRECATED - This group version of DaemonSet is deprecated by apps/v1beta2/DaemonSet. See the release notes for more information. DaemonSet represents the configuration of a daemon set.
FIELDS: apiVersion <string> APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources
kind <string> Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds
metadata <Object> Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata
spec <Object> The desired behavior of this daemon set. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status
status <Object> The current status of this daemon set. This data may be out of date by some window of time. Populated by the system. Read-only. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status
(2)Pod模板
.spec 唯一必需的字段是 .spec.template。
.spec.template 是一个 Pod 模板。 它与 Pod 具有相同的 schema,除了它是嵌套的,而且不具有 apiVersion 或 kind 字段。
Pod 除了必须字段外,在 DaemonSet 中的 Pod 模板必须指定合理的标签(查看 pod selector)。
在 DaemonSet 中的 Pod 模板必需具有一个值为 Always 的 RestartPolicy,或者未指定它的值,默认是 Always。