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
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
# 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