K8s 安装 Minikube

本地快速装一个微型的kubernetes环境, 翻墙的苦谁能懂?

mac 本地安装minikube环境

环境需求:

  • kubectl 本地做命令行控制用, 所有的命令操作都是通过它
  • vittualBox v5.1 + 更新到最新版本就对了
  • minikube 在本地搭建测试环境

翻墙有困难的可以参考一下这个 https://yq.aliyun.com/articles/221687

安装 kubectl

1
➜   brew install kubectl

下载最新 minikube 不建议使用brew安装, 首先版本不会是最新, 再者会出现莫名其妙的问题

1
2
3
➜   curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-darwin-amd64 && \
chmod +x minikube && \
sudo mv minikube /usr/local/bin/

默认 start 时运行的virtualBox 去官网下个最新的就行

启动, 最好把docker镜像指定到国内

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
➜  ~ minikube start --registry-mirror=https://registry.docker-cn.com
😄 minikube v1.0.1 on darwin (amd64)
💿 Downloading Minikube ISO ...
142.88 MB / 142.88 MB [============================================] 100.00% 0s
🤹 Downloading Kubernetes v1.14.1 images in the background ...
🔥 Creating virtualbox VM (CPUs=2, Memory=2048MB, Disk=20000MB) ...
📶 "minikube" IP address is 192.168.99.103
🐳 Configuring Docker as the container runtime ...
🐳 Version of container runtime is 18.06.3-ce
⌛ Waiting for image downloads to complete ...
✨ Preparing Kubernetes environment ...
💾 Downloading kubeadm v1.14.1
💾 Downloading kubelet v1.14.1
🚜 Pulling images required by Kubernetes v1.14.1 ...
🚀 Launching Kubernetes v1.14.1 using kubeadm ...
⌛ Waiting for pods: apiserver proxy etcd scheduler controller dns
🔑 Configuring cluster permissions ...
🤔 Verifying component health .....
💗 kubectl is now configured to use "minikube"
🏄 Done! Thank you for using minikube!
➜ ~ kubectl cluster-info
Kubernetes master is running at https://192.168.99.103:8443
KubeDNS is running at https://192.168.99.103:8443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.

如果Minikube ISO存在墙的问题, 就把iso下载后放到 ~/.minikube/cache/iso/

这时Mac上的docker不能用docker for Mac提供的了, 而是宿主机里面的docker, 切换命令为:

1
➜   eval $(minikube docker-env)

撤销更改

1
➜   eval $(minikube docker-env -u)

加载后台控制面板, 稍等一会, 自动打卡后台界面

1
➜   minikube dashboard

部署第一个应用

命令行部署
创建node.js 应用

创建文件 server.js

1
2
3
4
5
6
7
8
9
var http = require('http');

var handleRequest = function(request, response) {
console.log('Received request for URL: ' + request.url);
response.writeHead(200);
response.end('Hello World! V1');
};
var www = http.createServer(handleRequest);
www.listen(3000);

运行

1
node server.js   // 访问地址  http://localhost:3000

创建docker镜像
1
2
3
4
5
6
FROM node:8.10.0

EXPOSE 3000

COPY server.js .
CMD ["node", "server.js"]

构建镜像

1
➜ docker build -t hello-node:v1 .

如果出现Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running? 说明你忘了执行 eval $(minikube docker-env)
kube用的 docker 和你本地用的 docker 是两个位置, kube的在虚拟机里运行

创建 deployment

有了镜像就具备创建pod的条件, 通常来说不用直接创建 pod, 而是创建 deployment 或者 replication controller, 由他们来负责管理服务的运行, 规模缩放, 自动重启等等这些操作, 就单个pod来说是可以随时被销毁的, 不能作为稳定服务的保证

1
2
3
➜ kubectl run hello-node --image=hello-node:v1 --port=3000

➜ kubectl create deployment hello-node --image=hello-node:v1

查看当前deployment

1
2
3
➜ kubectl get deployments 
NAME READY UP-TO-DATE AVAILABLE AGE
hello-node 1/1 1 1 8m8s

ready 1/1 说明已经准备就绪了

查看 pod

1
2
3
➜  hellonode git:(master) ✗ kubectl get pods
NAME READY STATUS RESTARTS AGE
hello-node-5c58cb6dd4-h65fx 1/1 Running 0 8m40s

从这两条信息就能看出来, 每个pod都是带随机字符串的, 并不打算给人去操作, 我们主要专注在deploymentservice 的搭建

查看 deployment 描述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
➜ kubectl describe deployments/hello-node

Name: hello-node
Namespace: default
CreationTimestamp: Mon, 13 May 2019 14:17:03 +0800
Labels: run=hello-node
Annotations: deployment.kubernetes.io/revision: 1
Selector: run=hello-node
Replicas: 1 desired | 1 updated | 1 total | 1 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: run=hello-node
Containers:
hello-node:
Image: hello-node:v1
Port: 3000/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: hello-node-5c58cb6dd4 (1/1 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 11m deployment-controller Scaled up replica set hello-node-5c58cb6dd4 to 1

这里是对deployment的概览, Pod Template: 下就是每个pods的配置, 之后对部署的扩容都是基于这个去复制

到目前为止我们创建了deployment 而且也自动生成pod了, 可是服务并不能被访问到, 为什么? 因为端口没有对外暴露出来, 所以有了下一步

创建service

service 就是用来对我暴露服务的东西, 所有的 pod 都是在内网通信, 外部访问就得让 service 这层代理去转发过去, --type=LoadBalancer 就是指定转发为负载均衡模式, kubectl create service -h 查看更多, 这里不细讲

创建service

1
2
3
➜ kubectl expose deployment hello-node --type=LoadBalancer

➜ kubectl expose deployment hello-node --type=LoadBalancer --port=3000 // 这里指定端口

查看

1
2
3
4
➜ kubectl get service                                     
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hello-node LoadBalancer 10.111.18.151 <pending> 3000:31349/TCP 3s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3d

详细信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
➜ kubectl describe services hello-node 
Name: hello-node
Namespace: default
Labels: run=hello-node
Annotations: <none>
Selector: run=hello-node
Type: LoadBalancer
IP: 10.111.18.151
Port: <unset> 3000/TCP
TargetPort: 3000/TCP
NodePort: <unset> 31349/TCP
Endpoints: 172.17.0.7:3000
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>

NodePort 就是绑定在节点的那个端口上, 直接访问节点ip就行, 也可以用minikube命令 minikube service hello-node 自动帮你打开本地地址

扩展示例

线上肯定是有这种动态扩容的情况, 而且多实例之间滚动升级也不会停止服务

1
2
3
4
5
6
7
8
➜ kubectl scale deployments/hello-node --replicas=4
deployment.extensions/hello-node scaled
➜ hellonode git:(master) ✗ kubectl get pods
NAME READY STATUS RESTARTS AGE
hello-node-5c58cb6dd4-d2qq9 1/1 Running 0 18s
hello-node-5c58cb6dd4-h65fx 1/1 Running 0 51m
hello-node-5c58cb6dd4-jlzjw 1/1 Running 0 18s
hello-node-5c58cb6dd4-vmx4f 1/1 Running 0 18s

更新应用

重新构建一个node的镜像
service.js

1
2
3
4
5
6
7
8
9
var http = require('http');

var handleRequest = function(request, response) {
console.log('Received request for URL: ' + request.url);
response.writeHead(200);
response.end('Hello World! V2');
};
var www = http.createServer(handleRequest);
www.listen(3000);

1
➜ docker build -t hello-node:v2 .

设置 deployment 使用新镜像

1
➜ kubectl set image deployment/hello-node hello-node=hello-node:v2

查看每个pod的具体情况

1
➜ kubectl describe pods

再访问刚才的地址就能看到改变了

清除资源
1
2
➜ kubectl delete service hello-node
➜ kubectl delete deployments hello-node

经过上面一套操作下来, 应该也对k8s有了一个大致的印象了, 毕竟光看实践才是检验真理的唯一标准, 但是如果部署一个服务这样一个命令一个命令的敲是很要命的, 而且服务器这玩意, 轻易不会动, 时间一长就容易忘, 因此用配置文件去启动更加合理

通过 yaml 启动

如下: test-service.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
apiVersion: v1
kind: Service
metadata:
name: test-service
labels:
version: v2
run: hello-node
app: test-service
spec:
type: LoadBalancer
ports:
- port: 3001
targetPort: 3000
protocol: TCP
selector:
app: test-service
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-service
labels:
app: test-service
spec:
replicas: 2
selector:
matchLabels:
app: test-service
template:
metadata:
labels:
app: test-service
spec:
containers:
- name: node-pod
image: hello-node:v2
imagePullPolicy: IfNotPresent
ports:
- containerPort: 3000

执行

1
2
➜ kubectl create -f test-service.yaml
➜ minikube service test-service

这样通过配置文件就能启动了, 配置文件里里的字段后续我们再详细的讲一下

删除kubectl delete -f test-service.yaml

代码地址

相关资料

带你理解Kubernetes,部署一个Node应用
Kubernetes的三种外部访问方式:NodePort、LoadBalancer 和 Ingress
Minikube - Kubernetes本地实验环境
Kubernetes之kubectl常用命令
replication controller与deployment的区别
Kubenetes里pod和service绑定的实现方式
Kubernetes创建资源对象yaml文件例子
kubernetes/minikube github