《Kubernetes in Action》第二章笔记

《Kubernetes in Action》第二章笔记

容器实现隔离机制

  1. namspace 单独的系统视图(文件、进程、网络接口、主机名)
  2. cgroups 隔离资源(CPU、内存、网络带宽等)

虚拟机相较容器的优势

  • 内核。虚拟机运行在自己的内核上;容器调用同一个内核,会有安全隐患。

执行docker run

  1. 本机是否已存在该镜像
  2. 如果不存在则拉取
  3. 基于镜像创建容器
  4. 在容器里运行docker run 指定的命令
  5. 输出后进程终止,容器停止运行
    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

docker的tag是干什么用的

镜像会有多个版本,tag用来区分版本,每个版本有唯一的tag名。一般默认指定tag为latest这就是为什么总能看见xx:latest这种镜像名。

构建自己的镜像

  1. 创建Dockerfile(注意要跟你的文件同目录)
  2. docker build -t kubia .不要遗漏最后的. 这是要求基于当前目录构建一个叫kubia的镜像
  3. Docker在该目录中寻找Dockerfile并且根据里面的指令(由docker客户端上传目录文件到守护进程,由docker守护进程)来构建镜像(所以可以让客户端和守护进程分别在不同的机器上)

或者不通过Dockerfile而是在容器中运行命令后手动把最终状态作为新镜像

镜像分层

在拉取镜像的时候会出现多个pull complete,这就是一层一层的拉取。这些分层可以由不同的镜像共享。每一层下载时独立的,所以不用重复下载已经存在于机器上的分层。
在构建镜像时,Dockerfile中每一条单独指令都会创建一个新层。

  1. 拉取基础镜像所有分层后再创建一个新层并添加你的文件。
  2. 创建另一层来指定镜像被运行时所执行的命令。
  3. 最后一层会被标记为your_name:latest就是之前指定的kubia

列出本地所有镜像

docker 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 容器名会打印包含容器底层信息的长json

删除指令

  • 删除容器 docker rm 注意先stop
  • 删除镜像 docker rmi

id是个十六进制数

在容器内部运行shell

一个容器里还可以运行多个进程,如果镜像里包含了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守护进程

目前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 hub docker login
  • docker push xxx/kubia推送你的镜像
    这样其他人也能用了,或者用在其他机器上,只要docker run -p 8080:8080 -d xxx/kubia。这个应用使用的node.js是镜像内部安装的,所以主机并不需要安装node.js。应用每次都运行在完全一致的环境中。

使用minikube启动k8s集群(单节点)

安装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停止集群等命令

  • minikube stop停止集群
  • minikube delete删除集群
  • minikube dashboard弹出浏览器页面:集群概览
  • minikube addons list查看扩展插件列表

kubectl相关命令

  • kubectl get nodes查看集群中的节点状态(简单信息)
  • kubectl describe node xx查看节点的更多信息

kubectl的命令补全

  1. 安装bashcompletion@2(我是mac但是这里有个坑,使用brew install bash-completion来安装的是默认版本v1 对应 Bash3.2,kubectl 的补全脚本无法适配 bash-completion v1 和 Bash 3.2,必须为它配备 bash-completion v2 和 Bash 4.1+。所以需要brew install bash
  2. brew info bash-completion@2查看信息,会有一句话Add the following line to your ~/.bash_profile:把后面那句话给加到~/.bash_profile就可以了。然后source ~/.bash_profile
  3. 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就好了

K8s上运行第一个应用

  • 部署Node.js应用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是什么

pod是一组紧密相关的容器,它们运行在同一个工作节点以及同一个Linux命名空间中。拥有自己的IP、主机名、进程等,运行一个独立的应用程序(单个进程运行在单个容器,或者一个猪应用进程和其他支持进程每个进程都在自己的容器中运行)。所有容器运行在同一个逻辑机器上。
不能列出单个容器,pod是独立的k8s对象。

  • 查看pods kubectl get pods
  • 详细信息 kubectl describe pods

首先,kubectl向k8sAPI服务器发送REST HTTP请求,在集群中创建一个新的rc对象。然后,rc创建新的pod,调度器将它调度到一个工作节点上。kubectl看到pod被调度,告知docker从镜像中心拉取指定镜像。于是,下载镜像后docker创建并运行容器。调度后的pod立即运行。

访问web应用-通过服务

pod的ip地址是集群内部的,如果要从外部访问,需要通过服务对象公开它,即创建一个特殊的LoadBalancer类型的服务(yaml中写了)。(常规服务不行,只能内部访问)LoadBalancer类型的服务将创建一个外部的负载均衡。我们要通过这个负载均衡的公共ip来访问pod。

  • 暴露rc创建服务 kubectl expose rc kubia --type=LoadBalancer --name kubia-http --port=80 --target-port=8080
  • 列出服务 kubectl get services
    需要等待一段时间才会有EXTERNAL-IP。但是!!!minikube不支持LoadBalancer类型的服务,因此服务不会有外部IP。但是可以通过外部端口访问服务。可以运行minikube service kubia-http获取可以访问服务的ip和端口。直接会从浏览器弹出来。

应用将pod名称作为它的主机名。rc管理的pod通过一个服务向外暴露。pod包含任意数量的容器,容器内部是node.js进程,进程绑定到了8080端口,等待http请求。pod有自己独立的ip和主机名
客户通过固定ip连接到服务,不直接连接pod,服务确保其中一个pod接受连接,不管pod自己的ip。也就是到达服务的请求将被转发到属于该服务的一个容器的ip和端口。

pod水平伸缩(扩容)

  • 查看kubectl get replicationcontroller
  • 改变期望的副本数kubectl scale rc kubia --replicas=3
  • 再查看kubectl get pods会发现相应的pod数量改变。
    当多个应用实例运行时,如果再次请求服务的url就会随机切换pod。服务就作为负载均衡挡在前面。如果想要查看pod被调度到哪个节点上:

列出podIP和节点

kubectl get pods -o wide
查看细节kubectl describe pod kubia-hczji

你可能感兴趣的:(其他)