194 lines
6.6 KiB
Markdown
194 lines
6.6 KiB
Markdown
|
# Kubernetes 101
|
|||
|
|
|||
|
体验Kubernetes最简单的方法是跑一个nginx容器,然后使用kubectl操作该容器。Kubernetes提供了一个类似于`docker run`的命令`kubectl run`,可以方便的创建一个容器(实际上创建的是一个由deployment来管理的Pod):
|
|||
|
|
|||
|
```sh
|
|||
|
$ kubectl run --image=nginx nginx-app --port=80
|
|||
|
deployment "nginx-app" created
|
|||
|
$ kubectl get pods
|
|||
|
NAME READY STATUS RESTARTS AGE
|
|||
|
nginx-app-4028413181-cnt1i 1/1 Running 0 52s
|
|||
|
```
|
|||
|
|
|||
|
等到容器变成Running后,就可以各种`kubectl`命令来操作它了,比如
|
|||
|
|
|||
|
- `kubectl get` - 类似于`docker ps`,查询资源列表
|
|||
|
- `kubectl describe` - 类似于`docker inspect`,获取资源的详细信息
|
|||
|
- `kubectl logs` - 类似于`docker logs`,获取容器的日志
|
|||
|
- `kubectl exec` - 类似于`docker exec`,在容器内执行一个命令
|
|||
|
|
|||
|
```sh
|
|||
|
$ kubectl get pods
|
|||
|
NAME READY STATUS RESTARTS AGE
|
|||
|
nginx-app-4028413181-cnt1i 1/1 Running 0 6m
|
|||
|
$ kubectl exec nginx-app-4028413181-cnt1i ps aux
|
|||
|
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
|
|||
|
root 1 0.0 0.5 31736 5108 ? Ss 00:19 0:00 nginx: master process nginx -g daemon off;
|
|||
|
nginx 5 0.0 0.2 32124 2844 ? S 00:19 0:00 nginx: worker process
|
|||
|
root 18 0.0 0.2 17500 2112 ? Rs 00:25 0:00 ps aux
|
|||
|
$ kubectl describe pod nginx-app-4028413181-cnt1i
|
|||
|
Name: nginx-app-4028413181-cnt1i
|
|||
|
Namespace: default
|
|||
|
Node: boot2docker/192.168.64.12
|
|||
|
Start Time: Tue, 06 Sep 2016 08:18:41 +0800
|
|||
|
Labels: pod-template-hash=4028413181
|
|||
|
run=nginx-app
|
|||
|
Status: Running
|
|||
|
IP: 172.17.0.3
|
|||
|
Controllers: ReplicaSet/nginx-app-4028413181
|
|||
|
Containers:
|
|||
|
nginx-app:
|
|||
|
Container ID: docker://4ef989b57d0a7638ad9c5bbc22e16d5ea5b459281c77074fc982eba50973107f
|
|||
|
Image: nginx
|
|||
|
Image ID: docker://sha256:4efb2fcdb1ab05fb03c9435234343c1cc65289eeb016be86193e88d3a5d84f6b
|
|||
|
Port: 80/TCP
|
|||
|
State: Running
|
|||
|
Started: Tue, 06 Sep 2016 08:19:30 +0800
|
|||
|
Ready: True
|
|||
|
Restart Count: 0
|
|||
|
Environment Variables: <none>
|
|||
|
Conditions:
|
|||
|
Type Status
|
|||
|
Initialized True
|
|||
|
Ready True
|
|||
|
PodScheduled True
|
|||
|
Volumes:
|
|||
|
default-token-9o8ks:
|
|||
|
Type: Secret (a volume populated by a Secret)
|
|||
|
SecretName: default-token-9o8ks
|
|||
|
QoS Tier: BestEffort
|
|||
|
Events:
|
|||
|
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
|
|||
|
--------- -------- ----- ---- ------------- -------- ------ -------
|
|||
|
8m 8m 1 {default-scheduler } Normal Scheduled Successfully assigned nginx-app-4028413181-cnt1i to boot2docker
|
|||
|
8m 8m 1 {kubelet boot2docker} spec.containers{nginx-app} Normal Pulling pulling image "nginx"
|
|||
|
7m 7m 1 {kubelet boot2docker} spec.containers{nginx-app} Normal Pulled Successfully pulled image "nginx"
|
|||
|
7m 7m 1 {kubelet boot2docker} spec.containers{nginx-app} Normal Created Created container with docker id 4ef989b57d0a
|
|||
|
7m 7m 1 {kubelet boot2docker} spec.containers{nginx-app} Normal Started Started container with docker id 4ef989b57d0a
|
|||
|
|
|||
|
|
|||
|
$ kubectl logs nginx-app-4028413181-cnt1i
|
|||
|
127.0.0.1 - - [06/Sep/2016:00:27:13 +0000] "GET / HTTP/1.0 " 200 612 "-" "-" "-"
|
|||
|
127.0.0.1 - - [06/Sep/2016:00:27:15 +0000] "GET / HTTP/1.0 " 200 612 "-" "-" "-"
|
|||
|
```
|
|||
|
|
|||
|
## 使用yaml定义Pod
|
|||
|
|
|||
|
上面是通过`kubectl run`来启动了第一个Pod,但是`kubectl run`并不能支持所有的功能。在Kubernetes中,更经常使用yaml文件来定义资源,并通过`kubectl create -f file.yaml`来创建资源。比如,一个简单的nginx Pod可以定义为:
|
|||
|
|
|||
|
```yaml
|
|||
|
apiVersion: v1
|
|||
|
kind: Pod
|
|||
|
metadata:
|
|||
|
name: nginx
|
|||
|
labels:
|
|||
|
app: nginx
|
|||
|
spec:
|
|||
|
containers:
|
|||
|
- name: nginx
|
|||
|
image: nginx
|
|||
|
ports:
|
|||
|
- containerPort: 80
|
|||
|
```
|
|||
|
|
|||
|
前面提到,`kubectl run`并不是直接创建一个Pod,而是先创建一个Deployment资源(replicas=1),再由Deployment来自动创建Pod,这等价于这样一个配置:
|
|||
|
|
|||
|
```yaml
|
|||
|
apiVersion: extensions/v1beta1
|
|||
|
kind: Deployment
|
|||
|
metadata:
|
|||
|
labels:
|
|||
|
run: nginx-app
|
|||
|
name: nginx-app
|
|||
|
namespace: default
|
|||
|
spec:
|
|||
|
replicas: 1
|
|||
|
selector:
|
|||
|
matchLabels:
|
|||
|
run: nginx-app
|
|||
|
strategy:
|
|||
|
rollingUpdate:
|
|||
|
maxSurge: 1
|
|||
|
maxUnavailable: 1
|
|||
|
type: RollingUpdate
|
|||
|
template:
|
|||
|
metadata:
|
|||
|
labels:
|
|||
|
run: nginx-app
|
|||
|
spec:
|
|||
|
containers:
|
|||
|
- image: nginx
|
|||
|
name: nginx-app
|
|||
|
ports:
|
|||
|
- containerPort: 80
|
|||
|
protocol: TCP
|
|||
|
dnsPolicy: ClusterFirst
|
|||
|
restartPolicy: Always
|
|||
|
```
|
|||
|
|
|||
|
## 使用Volume
|
|||
|
|
|||
|
Pod的生命周期通常比较短,只要出现了异常,就会创建一个新的Pod来代替它。那容器产生的数据呢?容器内的数据会随着Pod消亡而自动消失。Volume就是为了持久化容器数据而生,比如可以为redis容器指定一个hostPath来存储redis数据:
|
|||
|
|
|||
|
```yaml
|
|||
|
apiVersion: v1
|
|||
|
kind: Pod
|
|||
|
metadata:
|
|||
|
name: redis
|
|||
|
spec:
|
|||
|
containers:
|
|||
|
- name: redis
|
|||
|
image: redis
|
|||
|
volumeMounts:
|
|||
|
- name: redis-persistent-storage
|
|||
|
mountPath: /data/redis
|
|||
|
volumes:
|
|||
|
- name: redis-persistent-storage
|
|||
|
hostPath:
|
|||
|
path: /data/
|
|||
|
```
|
|||
|
|
|||
|
Kubernetes volume支持非常多的插件,可以根据实际需要来选择:
|
|||
|
|
|||
|
* emptyDir
|
|||
|
* hostPath
|
|||
|
* gcePersistentDisk
|
|||
|
* awsElasticBlockStore
|
|||
|
* nfs
|
|||
|
* iscsi
|
|||
|
* flocker
|
|||
|
* glusterfs
|
|||
|
* rbd
|
|||
|
* cephfs
|
|||
|
* gitRepo
|
|||
|
* secret
|
|||
|
* persistentVolumeClaim
|
|||
|
* downwardAPI
|
|||
|
* azureFileVolume
|
|||
|
* vsphereVolume
|
|||
|
|
|||
|
## 使用Service
|
|||
|
|
|||
|
前面虽然创建了Pod,但是在kubernetes中,Pod的IP地址会随着Pod的重启而变化,并不建议直接拿Pod的IP来交互。那如何来访问这些Pod提供的服务呢?使用Service。Service为一组Pod(通过labels来选择)提供一个统一的入口,并为它们提供负载均衡和自动服务发现。比如,可以为前面的`nginx-app`创建一个service:
|
|||
|
|
|||
|
```yaml
|
|||
|
$ kubectl expose deployment nginx-app --type=NodePort --port=80 --target-port=80
|
|||
|
service "nginx-app" exposed
|
|||
|
$ kubectl describe service nginx-app
|
|||
|
Name: nginx-app
|
|||
|
Namespace: default
|
|||
|
Labels: run=nginx-app
|
|||
|
Selector: run=nginx-app
|
|||
|
Type: NodePort
|
|||
|
IP: 10.0.0.66
|
|||
|
Port: <unset> 80/TCP
|
|||
|
NodePort: <unset> 30772/TCP
|
|||
|
Endpoints: 172.17.0.3:80
|
|||
|
Session Affinity: None
|
|||
|
No events.
|
|||
|
```
|
|||
|
|
|||
|
这样,在cluster内部就可以通过`http://10.0.0.66`和`http://node-ip:30772`来访问nginx-app。而在cluster外面,只能通过`http://node-ip:30772`来访问。
|
|||
|
|
|||
|
|