《Kubernetes in Action》第二章笔记
docker run busybox echo "Hello world"
(这里的helloworld必须打对)Unable to find image 'busybox:latest' locally
latest: Pulling from library/busybox
aa2a8d90b84c: Pull complete
Digest: sha256:be4684e4004560b2cd1f12148b7120b0ea69c385bcc9b12a637537a2c60f97fb
Status: Downloaded newer image for busybox:latest
Hello world
镜像会有多个版本,tag用来区分版本,每个版本有唯一的tag名。一般默认指定tag为latest
这就是为什么总能看见xx:latest
这种镜像名。
docker build -t kubia .
不要遗漏最后的.
这是要求基于当前目录构建一个叫kubia的镜像或者不通过Dockerfile而是在容器中运行命令后手动把最终状态作为新镜像
在拉取镜像的时候会出现多个pull complete
,这就是一层一层的拉取。这些分层可以由不同的镜像共享。每一层下载时独立的,所以不用重复下载已经存在于机器上的分层。
在构建镜像时,Dockerfile中每一条单独指令都会创建一个新层。
your_name:latest
就是之前指定的kubiadocker images
docker run --name kubia-container -p 8080:8080 -d kubia
--name
创建叫这个名字的新容器-d
与命令行分离,在后台运行但是我的容器并没有运行起来,从docker桌面的log发现是app.js的语法错误,于是删除容器和镜像又重新创建了一遍,得到:
curl localhost:8080
You've hit 380fe46afa1d
ok
docker ps
(运行的容器,-a
则包含运行的和已停止的)docker images
docker inspect 容器名
会打印包含容器底层信息的长jsondocker rm
注意先stopdocker rmi
id是个十六进制数
一个容器里还可以运行多个进程,如果镜像里包含了bash shell那么也可以运行一个shell。
首先用-it
进行交互模式,i是标准输入流,t是分配一个伪终端。
docker exec -it kubia-container bash
于是可以看看容器内部的进程:
ps axu
得到这个样子的输出:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 1.2 614436 25812 ? Ssl 02:45 0:00 node app.js
root 12 0.0 0.1 20340 3220 pts/0 Ss 02:55 0:00 bash
root 19 0.0 0.1 17504 2048 pts/0 R+ 02:58 0:00 ps axu
可以用exit
来退出容器(不是停止容器)。
目前docker依赖于一些Linux内核特性(比如Cgroup与Namespace)所以必须运行在linux系统上,如果是mac就会自动创建一个linux虚拟机。那么如何登陆这个虚拟机呢?
我使用的是Docker Desktop,在设置->Resources->ADVANCED拉到最下边有虚拟机的位置,大概在/Users/xxx/Library/Containers/com.docker.docker/Data/vms/0/data
有个Docker.raw
文件。
但是我并没有找到网上文章里说的tty软连接,所以采用下面这个方法:
临时建一个最小化的debian容器,指定容器运行在pid=host命名空间下,然后该容器运行nsenter命令。
原理:
–rm表示在退出的时候就自动删除该容器;
–privileged表示允许该容器访问宿主机(也就是我们想要登录的VM)中的各种设备;
–pid=host表示允许容器共享宿主机的进程命名空间(namespace),或者通俗点儿解释就是允许容器看到宿主机中的各种进程;
nsenter是一个小工具允许我们进入一个指定的namespace然后运行指定的命令,ns=namespace,enter=进入。
namespace是容器技术的根基,基本上可以认为namespace就是一组隔离的资源,不同的进程可以看到不同的系统资源。
所以就可以看到运行中的之前的app.js(kubia)
/ # ps axu |grep app.js
6370 root 0:00 node app.js
25933 root 0:00 grep app.js
文件系统是独立的,进程树也是独立的,所以会看到进程id跟主机上的进程id不同。
Docker Hub
登陆之后可以往自己的镜像仓库推送镜像,但要按照Docker Hub的规则来标注。
docker tag kubia xxx/kubia
这会给同一个镜像创建一个额外的标签,指向同一个镜像id。
docker login
docker push xxx/kubia
推送你的镜像docker run -p 8080:8080 -d xxx/kubia
。这个应用使用的node.js是镜像内部安装的,所以主机并不需要安装node.js。应用每次都运行在完全一致的环境中。安装minikube之后,minikube start
。要花很久时间,保持耐心。
安装kubectl,展示集群信息kubectl cluster-info
kubectl cluster-info
Kubernetes master is running at https://192.168.99.100:8443
KubeDNS is running at https://192.168.99.100:8443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
kubectl命令行客户端通过向K8s API服务器发出REST请求来与集群交互。
minikube stop
停止集群minikube delete
删除集群minikube dashboard
弹出浏览器页面:集群概览minikube addons list
查看扩展插件列表kubectl get nodes
查看集群中的节点状态(简单信息)kubectl describe node xx
查看节点的更多信息brew install bash-completion
来安装的是默认版本v1 对应 Bash3.2,kubectl 的补全脚本无法适配 bash-completion v1 和 Bash 3.2,必须为它配备 bash-completion v2 和 Bash 4.1+。所以需要brew install bash
)brew info bash-completion@2
查看信息,会有一句话Add the following line to your ~/.bash_profile:
把后面那句话给加到~/.bash_profile
就可以了。然后source ~/.bash_profile
。export BASH_COMPLETION_COMPAT_DIR="/usr/local/etc/bash_completion.d" [[ -r "/usr/local/etc/profile.d/bash_completion.sh" ]] && . "/usr/local/etc/profile.d/bash_completion.sh"
如果你是用 Homebrew 安装的 kubectl(如上所述), 那么 kubectl 补全脚本应该已经安装到目录 /usr/local/etc/bash_completion.d/kubectl 中了。 这种情况下,你什么都不需要做。
emmm就好了
kubectl run kubia --image=xx/kubia --port=8080 --generator=run/v1
记得把xx换成自己的名字。unknown flag: --generator
。于是在v1.21中发现:Remove deprecated --generator, --replicas, --service-generator, --service-overrides, --schedule from kubectl run Deprecate --serviceaccount, --hostport, --requests, --limits in kubectl run (#99732, @soltysh)
好吧,已弃用。它的目的就是让k8s创建一个Repliaction Controller。
所以写了一个yaml(注意替换xxx)。
apiVersion: v1
kind: ReplicationController
metadata:
name: kubia
spec:
replicas: 3
template:
metadata:
name: kubia
labels:
app: kubia
spec:
containers:
- name: nodejs
image: xxx/kubia
---
apiVersion: v1
kind: Service
metadata:
name: kubia
spec:
type: LoadBalancer
selector:
app: kubia
ports:
- port: 80
targetPort: 8080
kubectl apply -f kubia-rc-and-service-v1.yaml
pod是一组紧密相关的容器,它们运行在同一个工作节点以及同一个Linux命名空间中。拥有自己的IP、主机名、进程等,运行一个独立的应用程序(单个进程运行在单个容器,或者一个猪应用进程和其他支持进程每个进程都在自己的容器中运行)。所有容器运行在同一个逻辑机器上。
不能列出单个容器,pod是独立的k8s对象。
kubectl get pods
kubectl describe pods
首先,kubectl向k8sAPI服务器发送REST HTTP请求,在集群中创建一个新的rc对象。然后,rc创建新的pod,调度器将它调度到一个工作节点上。kubectl看到pod被调度,告知docker从镜像中心拉取指定镜像。于是,下载镜像后docker创建并运行容器。调度后的pod立即运行。
pod的ip地址是集群内部的,如果要从外部访问,需要通过服务对象公开它,即创建一个特殊的LoadBalancer
类型的服务(yaml中写了)。(常规服务不行,只能内部访问)LoadBalancer类型的服务将创建一个外部的负载均衡。我们要通过这个负载均衡的公共ip来访问pod。
kubectl expose rc kubia --type=LoadBalancer --name kubia-http --port=80 --target-port=8080
kubectl get services
minikube service kubia-http
获取可以访问服务的ip和端口。直接会从浏览器弹出来。应用将pod名称作为它的主机名。rc管理的pod通过一个服务向外暴露。pod包含任意数量的容器,容器内部是node.js进程,进程绑定到了8080端口,等待http请求。pod有自己独立的ip和主机名
客户通过固定ip连接到服务,不直接连接pod,服务确保其中一个pod接受连接,不管pod自己的ip。也就是到达服务的请求将被转发到属于该服务的一个容器的ip和端口。
kubectl get replicationcontroller
kubectl scale rc kubia --replicas=3
kubectl get pods
会发现相应的pod数量改变。kubectl get pods -o wide
查看细节kubectl describe pod kubia-hczji