Kubernetes 入门实战 Part1

2023-08-23 18:59:51 浏览数 (1)

01 初识 Docker

代码语言:javascript复制
apt install -y docker.io
service docker start
usermod -aG docker ${USER}
代码语言:javascript复制
docker version
docker info
docker ps
docker pull busybox
# show all images
docker images

https://docs.docker.com/get-started/overview/

02 被隔离的进程

代码语言:javascript复制
docker pull alpine
docker run -it alpine sh
cat /etc/os-release

隔离资源,保证系统安全,提高资源的利用率。

资源隔离提供了三种技术:namespace、 cgroup、chroot(pivot_rott)。

03 容器化的应用

Build once, Run anywhere.

应用程序不再直接和操作系统打交道,而是封装成镜像,再交给容器环境去运行。

代码语言:javascript复制
# remove image
docker rmi busybox
# 开启一个交互式操作的 Shell
docker run -it busybox
# 在后台运行
docker run -d busybox
# 为容器起一个名字
docker run -d --name xxx busybox
# 不保存容器,只要运行完毕就自动清除
docker run --rm busybox echo "hello docker"

docker stop xxx
# remove container
docker rm xxx

# show all container
docker ps -a
docker exec xxx echo "hello docker"

05 镜像仓库

  • https://github.com/docker-library/official-images
  • https://hub.docker.com/u/library

用户名/应用名:标签 官方镜像用户名是 library

  • slim 经过精简的
  • fat 包含了较多的辅助工具
  • rc 候选版本,release candidate
代码语言:javascript复制
docker build -t
docker tag ngx-app chronolaw/ngx-app:1.0
docker push chronolaw/ngx-app:1.0

save 和 load 这两个镜像归档命令:

代码语言:javascript复制
docker save ngx-app:latest -o ngx.tar
docker load -i ngx.tar

06 打破次元壁

代码语言:javascript复制
docker run -d --rm --name ubu phusion/baseimage:jammy-1.0.1
echo "hello" > a.txt
# a.txt 拷贝到容器 tmp
docker cp a.txt ubu:/tmp
docker exec -it ubu bash
# 考出容器
docker cp ubu:/tmp/a.txt ./b.txt

容器和主机共享本地目录:

代码语言:javascript复制
# --mount
# -v /tmp:/tmp:ro 只读
docker run -d --rm -v /tmp:/tmp --name ubu phusion/baseimage:jammy-1.0.1
docker exec -it ubu bash
代码语言:javascript复制
docker pull python:alpine
docker run -it --rm -v `pwd`:/tmp python:alpine sh

网络模式:null host bridge

代码语言:javascript复制
# host
docker run -d --rm --net=host --name=ng nginx:alpine
docker exec ng ip addr
docker inspect ng | grep IPAddress
docker stop ng
代码语言:javascript复制
# bridge 默认模式
docker run -d --rm --name=ng nginx:alpine
docker inspect ng | grep IPAddress
# "IPAddress": "172.17.0.3"
docker run -d --rm --name=rd redis
docker inspect rd | grep IPAddress
# "IPAddress": "172.17.0.4"

分配服务端口号

代码语言:javascript复制
docker run -d -p 80:80 --rm nginx:alpine
docker run -d -p 8080:80 --rm nginx:alpine
# 分别“映射”到了两个容器里的 80 端口

07 玩转 Docker

Container Image Registry

https://registry.hub.docker.com/_/registry/

代码语言:javascript复制
docker run -d -p 5000:5000 registry
# 使用 docker tag 命令给镜像打标签再上传
docker tag nginx:alpine 127.0.0.1:5000/nginx:alpine
docker push 127.0.0.1:5000/nginx:alpine
# 本次重新拉取测试
docker rmi 127.0.0.1:5000/nginx:alpine
docker pull 127.0.0.1:5000/nginx:alpine

https://docs.docker.com/registry/spec/api/

代码语言:javascript复制
# Listing Repositories
curl 127.1:5000/v2/_catalog
# {"repositories":["nginx"]}
curl 127.1:5000/v2/nginx/tags/list
# {"name":"nginx","tags":["alpine"]}

registry 默认会把镜像存储在 Docker 内部目录 /var/lib/registry

搭建 WordPress:

代码语言:javascript复制
docker run -d --rm 
    --env MARIADB_DATABASE=db 
    --env MARIADB_USER=wp 
    --env MARIADB_PASSWORD=123 
    --env MARIADB_ROOT_PASSWORD=123 
    --name mariadb 
    mariadb:10
# 进入 mariadb
docker exec -it mariadb mysql -uwp -p123
# show mariadb ip
docker inspect mariadb | grep IPAddress
# "IPAddress": "172.17.0.2"

docker run -d --rm 
    --env WORDPRESS_DB_HOST=172.17.0.2 
    --env WORDPRESS_DB_USER=wp 
    --env WORDPRESS_DB_PASSWORD=123 
    --env WORDPRESS_DB_NAME=db 
    --name wp 
    wordpress:5
docker inspect wp | grep IPAddress
# "IPAddress": "172.17.0.4"
代码语言:javascript复制
vim wp.conf

server {
  listen 80;
  default_type text/html;
  location / {
      proxy_http_version 1.1;
      proxy_set_header Host $host;
      # wordpress server
      proxy_pass http://172.17.0.4;
  }
}
代码语言:javascript复制
# 感觉可以直接用 wordpress 的 80,无需再代理一次
docker run -d --rm 
    -p 80:80 
    -v `pwd`/wp.conf:/etc/nginx/conf.d/default.conf 
    --name ng 
    nginx:alpine
代码语言:javascript复制
# show logs
docker logs mariadb
docker logs ng
docker logs wp

08 入门篇总结

代码语言:javascript复制
docker pull alpine
docker run -it alpine sh
uname -a
# Linux de3852b4ec42 5.15.49-linuxkit #1 SMP Tue Sep 13 07:51:46 UTC 2022 x86_64 Linux

# Darwin V_YFANZHAO-MB1 19.6.0 Darwin Kernel Version 19.6.0: Tue Jun 21 21:18:39 PDT 2022; root:xnu-6153.141.66~1/RELEASE_X86_64 x86_64

构建自己的镜像:

https://github.com/chronolaw/k8s_study/blob/master/ch1/Dockerfile

代码语言:javascript复制
ARG IMAGE_BASE="nginx"
ARG IMAGE_TAG="1.21-alpine"

FROM ${IMAGE_BASE}:${IMAGE_TAG}

ENV PATH=$PATH:/tmp
ENV DEBUG=OFF

COPY ./default.conf /etc/nginx/conf.d/

RUN cd /usr/share/nginx/html 
    && echo "hello nginx" > a.txt

EXPOSE 8081 8082 8083

WORKDIR /etc/nginx
代码语言:javascript复制
docker build -t ngx-app:1.0 .
docker run -it --rm ngx-app:1.0 sh
docker save ngx-app:1.0 -o ngx.tar
docker load -i ngx.tar

09 Kubernetes 环境

容器编排 Container Orchestration

Kubernetes 就是一个生产级别的容器编排平台和集群管理系统。

https://minikube.sigs.k8s.io/docs/start/

代码语言:javascript复制
minikube version
# minikube version: v1.29.0
# commit: ddac20b4b34a9c8c857fc602203b6ba2679794d3

# 统一实验环境
minikube start --kubernetes-version=v1.23.3
# 查看状态
minikube status
minikube node list
# minikube 192.168.49.2

# 登录到这个节点上
minikube ssh
uname -a
# Linux minikube 5.15.49-linuxkit #1 SMP Tue Sep 13 07:51:46 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
ip add
代码语言:javascript复制
# minikube 管理 Kubernetes 集群环境
# kubectl 操作实际的 Kubernetes 功能
# install kubectl
minikube kubectl

minikube kubectl -- version
alias kubectl="minikube kubectl --"
kubectl version

# 启动一个镜像
kubectl run ngx --image=nginx:alpine

# like docker ps
kubectl get pod

https://kubernetes.io/zh/

10 Kubernetes 工作机制

Kubernetes 采用了现今流行的“控制面 / 数据面”(Control Plane / Data Plane)架构,集群里的计算机被称为“节点”(Node),可以是实机也可以是虚机,少量的节点用作控制面来执行集群的管理维护工作,其他的大部分节点都被划归数据面,用来跑业务应用。Master 节点实现管理控制功能,Worker 节点运行具体业务。

代码语言:javascript复制
kubectl get node
# NAME       STATUS   ROLES                  AGE   VERSION
# minikube   Ready    control-plane,master   38m   v1.23.3

# 查看 master Component pod
kubectl get pod -n kube-system
# NAME                               READY   STATUS    RESTARTS        AGE
# coredns-65c54cc984-4pckd           1/1     Running   0               40m
# etcd-minikube                      1/1     Running   0               40m
# kube-apiserver-minikube            1/1     Running   0               40m
# kube-controller-manager-minikube   1/1     Running   0               40m
# kube-proxy-88wt2                   1/1     Running   0               40m
# kube-scheduler-minikube            1/1     Running   0               40m
# storage-provisioner                1/1     Running   3 (6m39s ago)   40m
代码语言:javascript复制
# worker node
minikube ssh
# show kube-proxy
docker ps |grep kube-proxy
# show kubelet, not exist docker
ps -ef|grep kubelet
代码语言:javascript复制
# show addons list
minikube addons list

minikube dashboard

11 YAML

YAML 是 JSON 的超集。

Shell 脚本和 Dockerfile 可以很好地描述“命令式”(Imperative)。“声明式”(Declarative)注重结果。

apiserver 采用了 HTTP 协议的 URL 资源理念,API 风格也用 RESTful,被称为是“API 对象”了。

代码语言:javascript复制
# 查看 kubectl api-service 支持的所有对象
kubectl api-resources

# 显示出详细的命令执行过程
kubectl get pod --v=9
# 自带的 API 文档 https://kubernetes.io/docs/reference/kubernetes-api/
kubectl explain pod
kubectl explain pod.metadata

# 命令式
kubectl run ngx --image=nginx:alpine
# 转换为 YAML 声名式
kubectl run ngx --image=nginx:alpine --dry-run=client -o yaml > ngx-pod.yml
kubectl apply -f ngx-pod.yml
kubectl delete -f ngx-pod.yml

12 Pod

为了解决这样多应用联合运行的问题,同时还要不破坏容器的隔离,就需要在容器外面再建立一个“收纳舱”。

代码语言:javascript复制
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: ngx
  name: ngx
spec:
  containers:
    - image: nginx:alpine
      name: ngx
      resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}
代码语言:javascript复制
vim ngx-pod.yml
kubectl apply -f ngx-pod.yml
kubectl logs ngx
kubectl get pod
kubectl describe pod ngx

# cp file to pod
echo 'aaa' > a.txt
kubectl cp a.txt ngx:/tmp

# exec need --
kubectl exec -it ngx -- sh

13 Job CronJob 离线业务

“单一职责”的意思是对象应该只专注于做好一件事情,不要贪大求全,保持足够小的粒度才更方便复用和管理。

“组合优于继承”的意思是应该尽量让对象在运行时产生联系,保持松耦合,而不要用硬编码的方式固定对象的关系。

代码语言:javascript复制
kubectl create job echo-job --image=busybox --dry-run=client -o yaml > job.yml
代码语言:javascript复制
apiVersion: batch/v1
kind: Job
metadata:
  creationTimestamp: null
  name: echo-job
spec:
  template:
    metadata:
      creationTimestamp: null
    spec:
      containers:
        - image: busybox
          name: echo-job
          resources: {}
          # 补充输出
          command: ["/bin/echo"]
          args: ["hello", "world"]
      restartPolicy: Never
status: {}
代码语言:javascript复制
kubectl apply -f job.yml
kubectl get job
# NAME       COMPLETIONS   DURATION   AGE
# echo-job   1/1           16s        33s
kubectl get pod
# NAME             READY   STATUS      RESTARTS   AGE
# echo-job-g2bf6   0/1     Completed   0          68s
kubectl logs echo-job
# hello world
代码语言:javascript复制
apiVersion: batch/v1
kind: Job
metadata:
  creationTimestamp: null
  name: sleep-job
spec:
  # 设置 Pod 运行的超时时间
  activeDeadlineSeconds: 60
  # 设置 Pod 的失败重试次数
  backoffLimit: 2
  # Job 完成需要运行多少个 Pod,默认是 1
  completions: 4
  # 它与 completions 相关,表示允许并发运行的 Pod 数量,避免过多占用资源
  parallelism: 2

  template:
    metadata:
      creationTimestamp: null
    spec:
      containers:
        - image: busybox
          name: echo-job
          resources: {}
          # 随机休眠
          command:
            - sh
            - -c
            - sleep $(($RANDOM % 10   1)) && echo done
      restartPolicy: Never
status: {}
代码语言:javascript复制
kubectl apply -f sleep-job.yaml

kubectl get pod -w
# NAME              READY   STATUS      RESTARTS   AGE
# sleep-job-92m4d   0/1     Completed   0          30s
# sleep-job-g8pmj   0/1     Completed   0          15s
# sleep-job-tsncl   0/1     Completed   0          30s
# sleep-job-x4qlp   0/1     Completed   0          15s
代码语言:javascript复制
# cronjob
kubectl create cj echo-cj --image=busybox --schedule="*/1 * * * *" --dry-run=client -o yaml > echo-cj.yaml
代码语言:javascript复制
apiVersion: batch/v1
kind: CronJob
metadata:
  creationTimestamp: null
  name: echo-cj
spec:
  jobTemplate:
    metadata:
      creationTimestamp: null
      name: echo-cj
    spec:
      template:
        metadata:
          creationTimestamp: null
        spec:
          containers:
            - image: busybox
              name: echo-cj
              resources: {}
              # 补充输出
              command: ["/bin/echo"]
              args: ["hello", "world"]
          restartPolicy: OnFailure
  schedule: "*/1 * * * *"
status: {}
代码语言:javascript复制
kubectl apply -f echo-cj.yaml
kubectl get cj
# NAME      SCHEDULE      SUSPEND   ACTIVE   LAST SCHEDULE   AGE
# echo-cj   */1 * * * *   False     1        5s              8s
kubectl get pod
# NAME                     READY   STATUS      RESTARTS   AGE
# echo-cj-27942326-qng4j   0/1     Completed   0          93s
# echo-cj-27942327-vlrvs   0/1     Completed   0          33s

14 ConfigMap Secret 管理配置信息

代码语言:javascript复制
kubectl create cm info --from-literal=name=zhao --dry-run=client -o yaml > cm.yml
kubectl apply -f cm.yml
kubectl get cm
kubectl describe cm info
代码语言:javascript复制
kubectl create secret generic user --from-literal=name=root --dry-run=client -o yaml > secret.yml

# -n 去掉字符串里隐含的换行符
echo -n "root" | base64
kubectl apply -f secret.yml
kubectl get secret
kubectl describe secret user
代码语言:javascript复制
kubectl explain pod.spec.containers.env.valueFrom
代码语言:javascript复制
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: ngx
  name: ngx
spec:
  containers:
    - image: nginx:alpine
      name: ngx
      resources: {}
      env:
        - name: NAME
          valueFrom:
            configMapKeyRef:
              name: info
              key: name
        - name: SNAME
          valueFrom:
            secretKeyRef:
              name: user
              key: name
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}
代码语言:javascript复制
kubectl apply -f env-pod.yml
kubectl exec -it ngx -- sh

echo $NAME $SNAME
代码语言:javascript复制
# 以 Volume 的方式使用 ConfigMap/Secret
apiVersion: v1
kind: Pod
metadata:
  name: vol-pod
spec:
  # Volume 属于 Pod 与 containers 同级
  volumes:
    - name: cm-vol
      configMap:
        name: info
    - name: sec-vol
      secret:
        secretName: user
  containers:
    # 挂载到容器里的某个路径下
    - volumeMounts:
        - mountPath: /tmp/cm-items
          name: cm-vol
        - mountPath: /tmp/sec-items
          name: sec-vol
      image: nginx:alpine
      name: ngx
      resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}
代码语言:javascript复制
vim vol-pod.yml
kubectl apply -f vol-pod.yml
kubectl get pod
kubectl exec -it vol-pod -- sh

cat /tmp/cm-items/name
cat /tmp/sec-items/name
# ConfigMap 和 Secret 都变成了目录的形式,而它们里面的 Key-Value 变成了一个个的文件,而文件名就是 Key。

15 玩转 Kubernetes

搭建 WordPress 环境:

代码语言:javascript复制
# vim mariadb-pod.yml
apiVersion: v1
kind: ConfigMap
metadata:
  name: maria-cm
data:
  DATABASE: "db"
  USER: "wp"
  PASSWORD: "123"
  ROOT_PASSWORD: "123"

---
apiVersion: v1
kind: Pod
metadata:
  name: maria-pod
  labels:
    app: wordpress
    role: database
spec:
  containers:
    - image: mariadb:10
      name: maria
      imagePullPolicy: IfNotPresent
      ports:
        - containerPort: 3306
      envFrom:
        - prefix: "MARIADB_"
          configMapRef:
            name: maria-cm
代码语言:javascript复制
kubectl apply -f mariadb-pod.yml
# 获取 IP 地址需要加上参数 -o wide
kubectl get pod -o wide
# NAME        READY   STATUS    RESTARTS   AGE   IP           NODE       NOMINATED NODE   READINESS GATES
# maria-pod   1/1     Running   0          64s   172.17.0.5   minikube   <none>           <none>
代码语言:javascript复制
# vim wp-pod.yml
apiVersion: v1
kind: ConfigMap
metadata:
  name: wp-cm
data:
  # MariaDB Pod 的 IP
  HOST: "172.17.0.5"
  USER: "wp"
  PASSWORD: "123"
  NAME: "db"

---
apiVersion: v1
kind: Pod
metadata:
  name: wp-pod
  labels:
    app: wordpress
    role: website
spec:
  containers:
    - image: wordpress:5
      name: wp-pod
      imagePullPolicy: IfNotPresent
      ports:
        - containerPort: 80
      envFrom:
        - prefix: "WORDPRESS_DB_"
          configMapRef:
            name: wp-cm
代码语言:javascript复制
kubectl apply -f wp-pod.yml
kubectl get pod -o wide
# NAME        READY   STATUS    RESTARTS   AGE     IP           NODE       NOMINATED NODE   READINESS GATES
# maria-pod   1/1     Running   0          160m    172.17.0.5   minikube   <none>           <none>
# wp-pod      1/1     Running   0          2m47s   172.17.0.6   minikube   <none>           <none>
代码语言:javascript复制
# 本地的 “8080” 映射到 WordPress Pod 的“80”
kubectl port-forward wp-pod 8080:80 &
# Forwarding from 127.0.0.1:8080 -> 80
# Forwarding from [::1]:8080 -> 80
# fg

16 初级篇总结

代码语言:javascript复制
minikube version
minikube status
minikube start --kubernetes-version=v1.23.3
minikube node list

kubectl version
kubectl run ngx --image=nginx:alpine

# apiserver 等核心组件是在 kube-system 名字空间
kubectl get pod -n kube-system

kubectl api-resources
kubectl explain pod.metadata

export out="--dry-run=client -o yaml"
kubectl run ngx --image=nginx:alpine $out > pod.yml

kubectl apply -f ngx-pod.yml
kubectl get pod
kubectl logs ngx-pod
kubectl exec -it ngx-pod -- sh
kubectl delete -f ngx-pod

kubectl create job echo-job --image=busybox $out
kubectl apply -f job.yml
kubectl get job
kubectl get pod
kubectl logs echo-job-l52l7

kubectl create cj echo-cj --image=busybox --schedule="* * * * *" $out
kubectl apply -f cronjob.yml
kubectl get cj
kubectl get pod

kubectl create cm info --from-literal=k=v $out
kubectl get cm
kubectl describe cm info

kubectl create secret generic user --from-literal=name=root $out
kubectl get secret
kubectl describe secret user

echo cm9vdA== | base64 -d

References

  • chronolaw/k8s_study | GitHub

– EOF –

  • # kubernetes

0 人点赞