K8S 入门实战 (1)

发布时间 2023-12-15 21:16:46作者: 无涯的计算机笔记

Docker 安装
# 1. 查看机器信息,内核版本要求 3.8 以上
 $ uname -a
 Linux centos8 5.11.12-300.el8.aarch64 #1 SMP Fri Jul 30 12:03:15 CST 2021 aarch64 aarch64 aarch64 GNU/Linux
 
 # 2. 关闭 selinux
 $ setenforce Enforcing
 $ getenforce
 Enforcing
 
 # 3. 关闭防火墙
 $ systemctl stop firewalld
 
 # 4. 检查网络,保证系统可以访问外网
 $ ping baidu.com
 64 bytes from 39.156.66.10 (39.156.66.10): icmp_seq=2 ttl=128 time=40.2 ms
 
 # 5. 删除本地源
 $ rm /etc/yum.repos.d/local.repo
 
 # 6. 下载软件源配置文件
 $ curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
 
 # 7. 安装 epel 源
 $ yum install epel-release -y
 
 # 8. 安装 docker 包
 $ yum list docker --show-duplicates
 $ yum install -y yum-utils
 $ yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
 $ yum list docker-ce --show-duplicates
 $ sudo yum-config-manager \
     --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo
 
 # 9. 验证安装结果
 $ docker version
  • docker version

docker version 会输出 Docker 客户端和服务器各自的版本信息:

[hamming@centos8 ~]$ docker version
# docker 客户端信息
Client: Docker Engine - Community
 Version:           20.10.18
 API version:       1.41
 Go version:        go1.18.6
 Git commit:        b40c2f6
 Built:             Thu Sep  8 23:10:56 2022
 OS/Arch:           linux/arm64
 Context:           default
 Experimental:      true

# docker 引擎信息
Server: Docker Engine - Community
 Engine:
  Version:          20.10.18
  API version:      1.41 (minimum version 1.12)
  Go version:       go1.18.6
  Git commit:       e42327a
  Built:            Thu Sep  8 23:09:25 2022
  OS/Arch:          linux/arm64
  Experimental:     false
 containerd:
  Version:          1.6.8
  GitCommit:        9cd3357b7fd7218e4aec3eae239db1f68a5a6ec6
 runc:
  Version:          1.1.4
  GitCommit:        v1.1.4-0-g5fd4c4d
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0
  • docker info

docker info 会显示当前 Docker 系统相关的信息,例如 CPU、内存、容器数量、镜像数量、容器运行时、存储文件系统等等。

Client:
 Context:    default
 Debug Mode: false
 Plugins:
  app: Docker App (Docker Inc., v0.9.1-beta3)
  buildx: Docker Buildx (Docker Inc., v0.9.1-docker)
  compose: Docker Compose (Docker Inc., v2.10.2)

Server:
 Containers: 0 # 容器信息
  Running: 0
  Paused: 0
  Stopped: 0
 Images: 0
 Server Version: 20.10.18
 Storage Driver: overlay2 # 存储文件系统
  Backing Filesystem: xfs
  Supports d_type: true
  Native Overlay Diff: true
  userxattr: false
 Logging Driver: json-file
 Cgroup Driver: systemd
 Cgroup Version: 1
 Plugins:
  Volume: local
  Network: bridge host ipvlan macvlan null overlay
  Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
 Swarm: inactive
 Runtimes: io.containerd.runtime.v1.linux runc io.containerd.runc.v2
 Default Runtime: runc
 Init Binary: docker-init
 containerd version: 9cd3357b7fd7218e4aec3eae239db1f68a5a6ec6
 runc version: v1.1.4-0-g5fd4c4d
 init version: de40ad0
 Security Options:
  seccomp
   Profile: default
 Kernel Version: 5.11.12-300.el8.aarch64 # 内核
 Operating System: CentOS Linux 8 # 操作系统
 OSType: linux
 Architecture: aarch64 # 系统架构
 CPUs: 2 # 核数
 Total Memory: 1.419GiB # 内存
 Name: centos8
 ID: MQ5W:UARY:J7LZ:QZPC:B63Z:4XW5:IUJQ:U63U:JXJD:VNGJ:7HW6:P5DD
 Docker Root Dir: /data/docker
 Debug Mode: false
 Registry: https://index.docker.io/v1/
 Labels:
 Experimental: false
 Insecure Registries:
  registry.access.redhat.com
  quay.io
  127.0.0.0/8
 Registry Mirrors:
  https://q2gr04ke.mirror.aliyuncs.com/
 Live Restore Enabled: true
容器常用命令
# 查看容器,-a 参数可以查看已退出的容器
$ docker ps [-a] 

# 运行容器
$ docker run hello-world # 运行简单的 docker 容器
$ docker run -d nginx:alpine # 后台运行Nginx
$ docker run -d --name red_srv redis # 后台运行 Redis
$ docker run -it --name ubuntu 2e6 sh # 使用IMAGE ID,登录 Ubuntu18.04

# 在指定容器中执行命令
$ docker exec -it red_srv sh

# 停止容器运行
$ docker stop red_srv

# 开启容器运行
$ docker start red_srv

# 删除容器
$ docker rm red_srv

# 拷贝文件
# 将 host.txt 文件拷贝到容器中的 tmp 文件夹下面
$ docker cp host.txt 062:/tmp

# 将容器内的 container.txt 文件拷贝到本机
$ docker cp 062:/tmp/container.txt ./container.txt

# 目录挂载
# 将本机目录 /tmp 挂在到容器目录 /tmp
$ docker run -d --rm -v /tmp(host):/tmp(container) redis
docker 内部角色和工作流程

图片

docker 实际上是一个客户端 client ,它会与 Docker Engine 里的后台服务 Docker daemon 通信,而镜像存储在远端的仓库 Registry 里,客户端并不能直接访问镜像仓库。Docker client 通过 build、pull、run等命令向 Docker daemon 发送请求,而 Docker daemon 则是容器和镜像的“大管家”,负责从远端拉取镜像、在本地存储镜像,还有从镜像生成容器、管理容器等所有功能。

与虚拟机的区别

图片

容器和虚拟机的目的都是隔离资源,保证系统安全,然后是尽量提高资源的利用率。

虚拟机创建的时候会在物理机虚拟化出一套完整的计算机硬件,在里面还能够安装任意的操作系统,这内外两个系统也同样是完全隔离,互不干扰。

而在数据中心的服务器上,虚拟机软件(即图中的 Hypervisor)同样可以把一台物理服务器虚拟成多台逻辑服务器,这些逻辑服务器彼此独立,可以按需分隔物理服务器的资源,为不同的用户所使用。

从实现的角度来看,虚拟机虚拟化出来的是硬件,需要在上面再安装一个操作系统后才能够运行应用程序,而硬件虚拟化和操作系统都比较“重”,会消耗大量的 CPU、内存、硬盘等系统资源,但这些消耗其实并没有带来什么价值,属于“重复劳动”和“无用功”,不过好处就是隔离程度非常高,每个虚拟机之间可以做到完全无干扰。

容器(即图中的 Docker),直接利用了下层的计算机硬件和操作系统,因为比虚拟机少了一层,所以自然就会节约 CPU 和内存,显得非常轻量级,能够更高效地利用硬件资源。不过,因为多个容器共用操作系统内核,应用程序的隔离程度就没有虚拟机那么高了。

运行效率是容器相比于虚拟机最大的优势,对比图中可以看到,同样的系统资源,虚拟机只能跑 3 个应用,其他的资源都用来支持虚拟机运行了,而容器则能够把这部分资源释放出来,同时运行 6 个应用。

docker 镜像的本质

从功能上来说,docker 镜像和其他安装包一样,都打包了应用程序。不同的地方在于,docker 镜像包含了程序运行的所有环境配置。使得其具有很好的跨平台便携性和兼容性,做到一次编写,到处运行。

  • 镜像的内部机制

容器镜像内部并不是一个平坦的结构,而是由许多的镜像层组成,当你在执行 docker pull 命令的时候,Docker 会检查是否有从重复的层,如果本地已经存在就不会重复下载,以此节约磁盘和网络成本。

  • 以 nginx:alpine 镜像为例
[hamming@centos8 ~]$ docker pull nginx:alpine
 alpine: Pulling from library/nginx
 9b3977197b4f: Pull complete
 11e00b6b0b40: Pull complete
 45812000e2a5: Pull complete
 2e3e03d70957: Pull complete
 bb56ce0340f0: Pull complete
 a313facfd18d: Pull complete # 说明这个镜像一共有 6 层
 Digest: sha256:eb05700fe7baa6890b74278e39b66b2ed1326831f9ec3ed4bdc6361a4ac2f333
 Status: Downloaded newer image for nginx:alpine
 docker.io/library/nginx:alpine
 
 # 查看镜像信息
 [hamming@centos8 ~]$ docker inspect nginx:alpine

图片

Docker Hub

Docker Hub 是 Docker 公司搭建的官方 Registry 服务,和 GitHub 一样,几乎成为了容器世界的基础设施。

  • 如何在 Docker Hub 上面挑选镜像
  1. 带有 Official image 标记的镜像,表示镜像经过了 Docker 公司的认证,有专门的团队负责审核、发布和更新,质量上绝对可以放心。

  2. 带有 Verified publisher 标记,是认证发行商发布的自己打包的镜像,大厂质量也值得信赖。

  3. 非官方镜像一种是企业官方发布上去的虽然没有经过 Docker 认证(如 openResty)但是可以放心使用,另一种就是存粹的个人上传上去的,质量上没有保证。

在选择 docker 镜像的时候,除了需要参考以上几点,下载量、星数、还有更新历史,也是选择的一个一个重要参考指标,通常可以采用随大流的方法,选择下载数最多的那个镜像。

镜像增删改查
# 拉取镜像,镜像完整名字由名字和标签组成
 $ docker pull busybox:1.21-alpine
 
 # 查看 docker 中存储的所有镜像
 $ docker images
 
 # 删除镜像
 $ dcoker rmi busybox
线上上传自己的镜像
  1. 在 Docker Hub 上注册一个用户;

  2. 本机上使用 docker login 命令,用刚才注册的用户名和密码认证身份登录;

  3. 使用 docker tag 命令,给镜像改成带用户名的完整名字,表示镜像是属于这个用户的。或者简单一点,直接用 docker build -t 在创建镜像的时候就起好名字。

$ docker tag hello-world canghaimingue/hello-world:1.0
$ docker push canghaimingue/hello-world:1.0
离线环境保存自己的镜像

Docker 提供了 save 和 load 这两个镜像归档命令,可以把镜像导出成压缩包,或者从压缩包导入 Docker,而压缩包是非常容易保管和传输的,可以联机拷贝,FTP 共享,甚至存在 U 盘上随身携带。

# 把容器按照自己的需求个性完之后,就可以创建自己的镜像的
 # docker commit 容器id 镜像名称:版本号
 $ docker commit 07388cf54586 hello-world:1.0
 
 # 保存镜像文件
 #docker save 镜像名称:版本号 -o 压缩文件名称
 $ docker save hello-world:1.0 -o hello_world.tar
 
 # 加载镜像文件
 $ docker load -i hello_world.tar
Docker 网络模式

Docker 有 bridge、none、host、container 四种网络模式,提供网络隔离、端口映射、容器间互通网络等各种支持。

网络模式 参数 备注
host --net=host 容器和宿主机共享 network namespace。
container --net= 容器和另外一个容器共享 network namespace,K8S 中的 pod 就是多个容器共享一个 network namespace。
none --net=none 容器有独立的 network namespace,但没有对其进行任何网络设置,如分配 veth pair 和网桥连接,配置 IP 等。
bridge --net=bridage 默认为该模式,通过 -p 指定端口映射。
  • host

连接到 host 网络的容器会共享宿主机的网络栈,容器内的网络配置与宿主机一致。直接使用host网络好处就是性能,如果容器对网络有较高要求可以直接使用host网络。但是:使用host网络也会牺牲灵活性,host已经使用的端口容器中将无法使用。

  • container

创建的容器和已经存在的一个容器共享一个Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过lo网卡设备通信。

$ docker run -itd --network=container:busybox --name busybox_container busybox
 
 # 查看两个容器状态
 $ docker ps | grep busybox
 c0131db3ccb3   busybox   "sh"    3 hours ago   Up 3 hours   busybox_container
 1283b0f92e91   busybox   "sh"    8 hours ago   Up 8 hours   busybox

查看两个容器的网络配置,发现他们共用的同一个 ip

  • none

挂载这个网络下的容器仅有lo网络,没有其他网卡,也就不能与外界通信,适合对安全性要求较高且不需要联网的容器。如下所示

  • bridge

默认网络,运行容器时如果不指定网络类型就会使用 bridge 网络。

$ docker run -itd --name busybox busybox
$ docker inspect busybox # 查看容器信息,下图可以看到网络模式 bridge

执行命令 ifconfig 可以看到网络设备中多了一个 veth7d0ac61,这是 busybox 的虚拟网卡。

$ bridge link show | grep docker0
 
 9: veth0f1803c@if8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master docker0 state forwarding priority 32 cost 2
 17: veth2884210@if16: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master docker0 state forwarding priority 32 cost 2
 19: veth7d0ac61@if18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master docker0 state forwarding priority 32 cost 2

通过上面的命令可以看到, 这个虚拟网络设备挂在 docker0。我们再看看 busybox 内部的网络设备。

$ docker exec -it busybox ip l
 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
 18: eth0@if19: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
    link/ether 02:42:ac:07:05:04 brd ff:ff:ff:ff:ff:ff

实际上, eth0@if19veth7d0ac61@if18 是一对 veto pair 设备,在虚拟网络中充当着桥梁的角色,实现容器件的网络通行。

Dockerfile 的编写
关键字 作用 备注
FROM 指定基础镜像 指定 dockerfile 基于那个 image 构建
MAINTAINER 作者信息 用来标明这个 dockerfile 谁写的
LABEL 标签 用来标明 dockerfile 的标签 可以使用 Label 代替 Maintainer 最终都是在 docker image 基本信息中可以查看
RUN 执行命令 执行一段命令 默认是 /bin/sh 格式: RUN command 或者 RUN ["command" , "param1","param2"]
CMD 容器启动命令 提供启动容器时候的默认命令 和 ENTRYPOINT 配合使用.格式 CMD command param1 param2 或者 CMD ["command" , "param1","param2"],只能有一个,有多个的时候最后一个生效。
ENTRYPOINT 入口 一般在制作一些执行就关闭的容器中会使用
COPY 复制文件 build 的时候复制文件到 image 中
ADD 添加文件 build 的时候添加文件到 image 中 不仅仅局限于当前build上下文 可以来源于远程服务
ENV 环境变量 指定 build 时候的环境变量 可以在启动的容器的时候 通过-e覆盖 格式 ENV name=value
ARG 构建参数 构建参数 只在构建的时候使用的参数 如果有ENV 那么ENV的相同名字的值始终覆盖 arg 的参数
VOLUME 定义外部可以挂载的数据卷 指定build的image那些目录可以启动的时候挂载到文件系统中 启动容器的时候使用 -v 绑定 格式 VOLUME ["目录"]
EXPOSE 暴露端口 定义容器运行的时候监听的端口 启动容器的使用-p来绑定暴露端口 格式: EXPOSE 8080 或者 EXPOSE 8080/udp
WORKDIR 工作目录 指定容器内部的工作目录 如果没有创建则自动创建 如果指定/ 使用的是绝对地址 如果不是/开头那么是在上一条workdir的路径的相对路径
USER 指定执行用户 指定build或者启动的时候 用户 在RUN CMD ENTRYPONT执行的时候的用户
HEALTHCHECK 健康检查 指定监测当前容器的健康监测的命令 基本上没用 因为很多时候 应用本身有健康监测机制
ONBUILD 触发器 当存在ONBUILD关键字的镜像作为基础镜像的时候 当执行FROM完成之后 会执行 ONBUILD的命令 但是不影响当前镜像 用处也不怎么大
STOPSIGNAL 发送信号量到宿主机 该STOPSIGNAL指令设置将发送到容器的系统调用信号以退出。
SHELL 指定执行脚本的shell 指定RUN CMD ENTRYPOINT 执行命令的时候 使用的shell
  • Dockerfile 样例
# base image
 FROM centos:7
 
 # MAINTAINER
 MAINTAINER frost <example@163.com>
 
 # put nginx-1.12.2.tar.gz into /usr/local/src and unpack nginx
 ADD nginx-1.12.2.tar.gz /usr/local/src
 
 # install utils
 RUN yum install -y gcc gcc-c++ glibc make autoconf openssl openssl-devel
 RUN yum install -y libxslt-devel -y gd gd-devel GeoIP GeoIP-devel pcre pcre-devel
 RUN useradd -M -s /sbin/nologin nginx
 
 # change dir to /usr/local/src/nginx-1.12.2
 WORKDIR /usr/local/src/nginx-1.12.2
 
 # execute command to compile nginx
 RUN ./configure --user=nginx --group=nginx --prefix=/usr/local/nginx     \
 --with-file-aio  --with-http_ssl_module  --with-http_realip_module   \
     --with-http_addition_module    --with-http_xslt_module               \
     --with-http_image_filter_module    --with-http_geoip_module           \
     --with-http_sub_module  --with-http_dav_module --with-http_flv_module \
     --with-http_mp4_module --with-http_gunzip_module                     \
     --with-http_gzip_static_module  --with-http_auth_request_module       \
     --with-http_random_index_module   --with-http_secure_link_module     \
     --with-http_degradation_module   --with-http_stub_status_module
    && make && make install
 
 ENV PATH /usr/local/nginx/sbin:$PATH
 
 EXPOSE 80
 
 ENTRYPOINT ["nginx"]
 
 CMD ["-g","daemon off;"]
报错问题及解决

问题1:docker 容器修改时间 date -s 报错 date: cannot set date: Operation not permitted

# 原因:在容器中没有操作权限,在容器启动时授权即可
 
 # 解决:
 $ docker stop 5cf4eb29c8ed # 停止容器
 $ docker run -itd --privileged=true -p 8080:80 nginx:latest # 重新启动,授权

问题2:更新 docker 软件失败(apt update 报错)

E: Release file for http://security.debian.org/debian-security/dists/bullseye-security/InRelease is not valid yet (invalid for another 19h 21min 31s). Updates for this repository will not be applied.

 # 原因:网络和本机系统时间不一致,所以导致无法更新源
 
 # 解决:更新一下 docker 时间即可
 
 $ tzselect
 依次选择4->9->1->1 #Asia->China-> Beijing->yes
 
 $ sudo date -s MM/DD/YY //修改日期
 $ sudo date -s hh:mm:ss //修改时间
 $ sudo hwclock --systohc //修改生效

问题3:无法连接到 docker daemon

# 原因:我的是 docker 没有设置开机自启动
 
 $ systemctl enable docker
 $ systemctl start docker
 $ vi /etc/docker/daemon.json # 配置参数参考官方文档
 {
   "graph": "/data/docker",
   "storage-driver": "overlay2",
   "insecure-registries": ["registry.access.redhat.com","quay.io"],
   "registry-mirrors": ["https://q2gr04ke.mirror.aliyuncs.com"],
   "bip": "172.7.5.1/24",
   "exec-opts": ["native.cgroupdriver=systemd"],
   "live-restore": true
 }
 
 # 重启docker让配置生效
 $ systemctl reset-failed docker.service
 $ systemctl start docker.service
 $ systemctl restart docker
 # 如果失败了,systemctl status docker查看报错信息
 $ docker info
 
 # 场景二:https://blog.csdn.net/m0_38088330/article/details/125343432
参考资料

关注公众号一起学习——无涯的计算机笔记