Linux、Docer、K8S相关面试题及解答

Linux、Docer、K8S相关面试题及解答

  • 1 参考资料
  • 2 Linux
    • 2.1 Linux常见命令
    • 2.2 Linux查看端口的命令
    • 2.3 Linux查看当前连接数的命令
    • 2.4 查找指定字符串
    • 2.5 读取操作系统环境变量
    • 2.6 添加环境变量
      • 2.6.1 系统环境相关,涉及全局的环境变量
      • 2.6.2 应用程序相关,某些程序使用的环境变量
      • 2.6.3 /etc/profile和/etc/profile.d/的区别
    • 2.7 Linux下普通文件和可执行文件有什么区别
    • 2.8 Linux下进程间通信有几种方式
    • 2.9 Linux下僵尸进程和孤儿进程是怎么产生的
    • 2.10 Linux在使用TOP看CPU时负载和使用率有什么区别
    • 2.11 Linux查看网络带宽的命令
    • 2.12 Linux软连接和硬连接的区别
    • 2.13 Linux中TCP的配置参数有哪些
    • 2.14 Linux查看当前连接服务器的前10位Ip
    • 2.15 Linux理论上最多能开多少个端口?
    • 2.16 假如服务器有瓶颈,你一般看哪些指标?你通过什么命令去看看哪些指标?
    • 2.17 Linux下使用free查看内存,这个可用内存是怎么看的?真正可用的内存是有哪些?
    • 2.18 用没有用过Linux作为路由器使用?
    • 2.19 你对Linux系统的node指标的理解是怎么样的?比如负载。(待进一步验证)
    • 2.20 这个node的值它一般到多大是算高?需要介入排查呢?
    • 2.21 系统指标采集,比如你需要你用go写一个agent,采集agent,那采集这些系统指标的一般的实现方法大概有哪些?(待进一步验证)
    • 2.22 你怎么用go代码去拿这些数据呢?(待进一步验证)
    • 2.23 在linux服务器上的话一般是用什么命令要看日志?
    • 2.24 每周定时备份一下MySQL的一个数据库,shell脚本该怎么写。
  • 3 Docker
    • 3.1 Docker特点 / 优势
    • 3.2 Docker架构
    • 3.3 Docker底层原理
    • 3.4 Docker镜像分层
    • 3.5 Docker Dockfile
      • 3.5.1 Docker Dockfile完整示例
    • 3.6 Docker Compose
      • 3.6.1 Docker Compose常用命令
      • 3.6.2 Docker Compose构建golang服务和MySQL数据库的示例
    • 3.7 Docker Swarm
      • 3.7.1 Docker Swarm常用命令
      • 3.7.2 Docker Swarm构建golang服务和MySQL数据库的示例
    • 3.8 Docker Stack
      • 3.8.1 Docker Stack常用命令
      • 3.8.2 Docker Stack构建golang服务和MySQL数据库的示例
    • 3.9 Dockfile 、Compose、Swarm、Stack区别
    • 3.10 Docker的隔离机制
    • 3.11 Docker的网络模式
    • 3.12 Docker命令
      • 3.12.1 Docker常用命令
      • 3.12.2 Docker挂载文件的命令
      • 3.12.3 Docker中查看Pod日志的命令
      • 3.12.4 Docker崩溃后自动重启的命令
      • 3.12.5 Docker打包镜像的操作【golang项目】
      • 3.12.6 Docker构建镜像的命令
    • 3.13 `Docker Compose`部署的服务,如果有一个挂了,它是怎么重新发送到正常服务里的,怎么实现的?
    • 3.14 Docker与虚拟机的区别
    • 3.15 Docker容器有几种状态
    • 3.16 DockerFile中的命令COPY和ADD命令有什么区别
    • 3.17 如何批量清理临时镜像文件
    • 3.18 如何查看镜像支持的环境变量
    • 3.19 本地的镜像文件都存放在哪里
    • 3.20 容器退出后,通过docker ps命令查看不到,数据会丢失么
    • 3.21 如何停止所有正在运行的容器
    • 3.22 如何清理批量后台停止容器
    • 3.23 如何临时退出一个正在交互的容器的终端,而不终止它
    • 3.24 很多应用容器都是默认后台运行的,怎么查看它们的输出和日志信息
    • 3.25 使用docker port命令映射容器的端口时,系统报错Error:NO public port ‘80’ published for …,是什么意思
    • 3.26 可以在一个容器中同时运行多个应用进程吗
    • 3.27 如何控制容器占用系统资源(CPU,内存)的份额
    • 3.28 从非官方仓库(如:dl.dockerpool.com)下载镜像的时候,有时候会提示"Error:Invaild registry endpointhttps://dl.docker.com:5000/v1/…"
    • 3.29 Docker的配置文件放在那里?如何修改配置
    • 3.30 如何更改docker的默认存储设置
    • 3.31 Docker与LXC(Linux Container)有何不同
    • 3.32 Docker与Vagrant有何不同
    • 3.33 开发环境中Docker与Vagrant该如何选择
    • 3.34 如何将一台宿主机的docker环境迁移到另外一台宿主机
    • 3.35 Docker镜像联合文件系统
    • 3.36 Docker是安全的么
    • 3.37 如何清理后台停止的容器
    • 3.38 当启动容器的时候提示:exec format error?如何解决问题
    • 3.39 如何退出一个镜像的bash,而不终止它
    • 3.40 如何退出容器时候自动删除
    • 3.41 Docker里面如何做监控?
    • 3.42 Docker容器的项目怎么去做一个上线升级替换?
  • 4 K8S(V1.28)
    • 4.1 Kubernetes特性
    • 4.2 为什么需要Kubernetes,它能做什么
    • ※ 4.3~4.6 都是概念解释,和官网内容一致
    • 4.3 Kubernetes对象
      • 4.3.1 Kubernetes对象
        • 4.3.1.1 理解Kubernetes对象
        • 4.3.1.2 服务器端字段验证
      • 4.3.2 Kubernetes 对象管理
      • 4.3.3 对象名称和 ID
      • 4.3.4 标签和选择算符
      • 4.3.5 NameSpace
      • 4.3.6 注解
      • 4.3.7 字段选择器
      • 4.3.8 Finalizers
      • 4.3.9 属主与附属
      • 4.3.10 推荐使用的标签
    • 4.4 Kubernetes组件
      • 4.4.1 控制平面组件(Control Plane Components)
        • 4.4.1.1 kube-apiserver
        • 4.4.1.2 etcd
        • 4.4.1.3 kube-scheduler
        • 4.4.1.4 kube-controller-manager
        • 4.4.1.5 cloud-controller-manager【可选】
      • 4.4.2 Node组件
        • 4.4.2.1 kubelet
        • 4.4.2.2 kube-proxy
        • 4.4.2.3 容器运行时(Container Runtime)
    • 4.5 插件(Addons)
      • 4.5.1 DNS
      • 4.5.2 Web 界面(仪表盘)
      • 4.5.3 容器资源监控
      • 4.5.4 集群层面日志
    • 4.6 Kubernetes API
      • 4.6.1 OpenAPI 规范
      • 4.6.2 持久化
      • 4.6.3 API 发现
      • 4.6.4 API组和版本控制
      • 4.6.5 API 扩展
    • ※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※

1 参考资料

参考1:K8S、Docker面试题整理

2 Linux

2.1 Linux常见命令

  1. ls:列出目录中的文件和子目录。
  2. pwd(print work directory):显示当前工作目录的路径。
  3. cd:更改当前工作目录。
  4. mkdir:创建新目录。
  5. rm:删除文件或目录。
    rm file_name
    rm -r directory_name  # 递归删除目录及其内容
    
  6. cp:复制文件或目录。
  7. mv:移动文件或目录,也可用于重命名。
  8. touch:创建新文件或更新文件的时间戳。
  9. cat:查看文件内容。
  10. more/less:逐页查看文件内容。
  11. head/tail:查看文件的前几行或后几行。
    head -n 10 file_name  # 查看前10行
    tail -n 10 file_name  # 查看后10行
    
  12. grep:在文件中搜索特定文本。
    grep "search_text" file_name
    
  13. find:查找文件或目录。
    find /path/to/search -name "file_name"
    
  14. chmod:修改文件或目录的权限。
  15. chown:更改文件或目录的所有者。
  16. ps:显示当前运行的进程。
  17. kill:终止正在运行的进程。
  18. top/htop:显示系统资源使用情况和进程信息。
  19. df:查看磁盘空间使用情况。df命令是统计磁盘分区整体的使用情况。
    df -h /path/to/folder # 以人类可读的方式显示磁盘空间(h:human)
    
    执行示例:
    [root@standalone soft]# df -h
    文件系统                 容量  已用  可用 已用% 挂载点
    devtmpfs                 2.9G     0  2.9G    0% /dev
    tmpfs                    2.9G     0  2.9G    0% /dev/shm
    tmpfs                    2.9G   12M  2.9G    1% /run
    tmpfs                    2.9G     0  2.9G    0% /sys/fs/cgroup
    /dev/mapper/centos-root   36G   11G   25G   32% /
    /dev/sda1               1014M  195M  820M   20% /boot
    tmpfs                    579M     0  579M    0% /run/user/0
    
  20. du:查看文件夹使用情况。du命令是统计文件或目录及其子目录的硬盘空间使用情况,一般可以帮我们快速定位目录下是否存在超大文件或其他特殊大小的文件。
    du -h /path/to/folder # 以人类可读的方式显示目录大小
    
    • 直接执行du -h命令,默认是显示当前目录及其所有子目录的硬盘空间使用情况,显示的会比较多。
    • du -sh /path/to/folder命令,只输出总计大小,不显示子文件详情。
    • du -h /path/to/folder | grep -v '/exclude_folder'排除指定子文件夹。
      执行示例:
    [root@standalone opt]# du -sh /opt/soft/
    3.7G    /opt/soft/
    [root@standalone opt]# du -sh soft/
    3.7G    soft/
    [root@standalone opt]# du -sh soft
    3.7G    soft
    
  21. wget/curl:下载文件或内容。
    wget URL
    curl -O URL
    

Linux系统有数百个命令可供使用,每个命令都有不同的选项和用途。可以使用man命令来查看每个命令的手册页,以获取更多详细信息和选项。例如,要查看ls命令的手册页,可以运行man ls

2.2 Linux查看端口的命令

查看外网映射端口的命令

  • 查询防火墙有哪些端口是开启的:firewall-cmd --list-port
  • 防火墙开放指定端口:firewall-cmd --zone=public --add-port=2181/tcp --permanent
  • 重启防火墙:firewall-cmd --reload
  • 查询防火墙是否开启指定端口号:firewall-cmd --query-port=2181/tcp(yes:端口开启成功,no:端口开启失败)

  1. netstat:使用netstat命令可以查看网络统计信息,包括打开的端口。要查看所有端口的状态,可以运行以下命令:
    netstat -tuln
    #这将显示所有TCP (-t) 和UDP (-u) 端口的监听 (-l) 和数字 (-n) 格式。
    
    执行示例:
    [root@standalone opt]# netstat -tuln
    Active Internet connections (only servers)
    Proto Recv-Q Send-Q Local Address           Foreign Address         State
    tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN
    tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN
    tcp6       0      0 :::9000                 :::*                    LISTEN
    tcp6       0      0 :::9004                 :::*                    LISTEN
    tcp6       0      0 :::9005                 :::*                    LISTEN
    tcp6       0      0 :::9009                 :::*                    LISTEN
    tcp6       0      0 :::22                   :::*                    LISTEN
    tcp6       0      0 ::1:25                  :::*                    LISTEN
    tcp6       0      0 :::8123                 :::*                    LISTEN
    udp        0      0 127.0.0.1:323           0.0.0.0:*
    udp6       0      0 ::1:323                 :::*
    
  2. ssss命令也可以用来查看套接字统计信息。要查看所有监听的TCP端口,可以运行以下命令:
    ss -tuln
    #这与netstat的输出类似,但ss命令更现代和高效。
    
    执行示例:
    [root@standalone opt]# ss -tuln
    Netid State      Recv-Q Send-Q                                             Local Address:Port                                                            Peer Address:Port
    udp   UNCONN     0      0                                                      127.0.0.1:323                                                                        *:*
    udp   UNCONN     0      0                                                          [::1]:323                                                                     [::]:*
    tcp   LISTEN     0      128                                                            *:22                                                                         *:*
    tcp   LISTEN     0      100                                                    127.0.0.1:25                                                                         *:*
    tcp   LISTEN     0      128                                                         [::]:9000                                                                    [::]:*
    tcp   LISTEN     0      128                                                         [::]:9004                                                                    [::]:*
    tcp   LISTEN     0      128                                                         [::]:9005                                                                    [::]:*
    tcp   LISTEN     0      128                                                         [::]:9009                                                                    [::]:*
    tcp   LISTEN     0      128                                                         [::]:22                                                                      [::]:*
    tcp   LISTEN     0      100                                                        [::1]:25                                                                      [::]:*
    tcp   LISTEN     0      128                                                         [::]:8123                                                                    [::]:*
    
  3. lsoflsof命令可以列出打开的文件,包括网络套接字。要查看某个特定端口的使用情况,可以运行以下命令(以80端口为例):
    lsof -i :80
    
  4. nmapnmap是一个网络扫描工具,可以用来扫描主机上的端口。要扫描某个主机上的所有端口,可以运行以下命令(以主机IP为例):
    nmap -p- IP_address
    #这将扫描主机上的所有端口,并显示它们的状态。
    
  5. iptables:如果使用防火墙规则,可以使用iptables命令来查看规则中开放的端口。以下是一个示例命令,用于查看当前防火墙规则中的端口:
    iptables -L -n
    

2.3 Linux查看当前连接数的命令

要查看当前连接数和连接状态,可以使用以下命令:

  1. ss命令ss命令是一个功能强大的工具,可用于查看当前系统的连接状态。要查看当前连接数,可以运行以下命令:
ss -tuln
这将显示所有TCP连接的详细信息,包括本地地址、远程地址、状态等。
  1. netstat命令:使用netstat命令也可以查看当前连接数和连接状态。要查看所有TCP连接的信息,可以运行以下命令:
netstat -tuln
这将显示所有TCP连接的详细信息,类似于ss命令的输出。
  1. iftop命令iftop命令是一个交互式的实时网络带宽监视工具,它可以显示当前连接数以及网络流量。要安装并使用iftop,可能需要先通过包管理器安装它(例如,使用apt或yum)。安装后,只需运行以下命令以启动iftop
iftop
#iftop将显示当前连接数以及网络流量的实时信息。

这些命令将帮助我们查看当前系统上的连接数和连接状态。可以根据需要选择其中一个命令来使用。如果需要更详细的连接信息,可以查阅相应命令的手册页,以了解更多选项和用法。例如,可以使用man ssman netstat来查看ssnetstat命令的手册页。

2.4 查找指定字符串

  1. grep命令grep是一个非常强大的文本搜索工具,可以用来查找文件中的字符串。以下是基本用法:
    grep "search_string" file_name
    
    例如,要在文件example.txt中查找字符串"hello",可以运行:
    grep "hello" example.txt
    
    grep还支持许多选项,例如忽略大小写、递归搜索目录等。可以使用man grep来查看更多选项和用法。
  2. find命令find命令用于在文件系统中查找文件和目录。可以与-exec选项结合使用grep来查找包含特定字符串的文件。例如:
    find /path/to/search -type f -exec grep -l "search_string" {} \;
    
    这将在/path/to/search目录及其子目录中查找包含"search_string"的文件,并列出它们的文件名。
  3. ack/ag命令:如果安装了ack(又称为ack-grep)或ag(又称为The Silver Searcher),它们是更高级的文本搜索工具,支持更多选项和正则表达式。安装后,可以运行以下命令来搜索字符串:
    1. 使用ack
      ack "search_string" file_name_or_directory
      
    2. 使用ag
      ag "search_string" file_name_or_directory
      
    这些工具通常比grep更快速和强大。
  4. grep命令递归搜索目录:如果要递归搜索目录中的文件,可以使用grep-r-R选项。例如:
    grep -r "search_string" /path/to/search
    
    这将在指定目录及其子目录中搜索包含"search_string"的文件。

2.5 读取操作系统环境变量

一个二进制程序(比如说叫hello),在运行时,需要读取操作系统的环境变量“CONFIG_PATH”,我们希望运行这个二进制程序,并且只对运行该程序的命令设置CONFIG_PATH环境变量为/home。该命令应该是怎么样的?

回答:
可以使用echo命令来读取操作系统环境变量的值。操作系统环境变量是一些全局设置,用于存储与系统操作和配置相关的信息。以下是如何读取环境变量的示例:

  1. 读取一个环境变量的值,使用$符号后跟环境变量的名称来读取其值。例如,要读取PATH环境变量的值,可以运行以下命令:
    echo $PATH
    #这将显示PATH环境变量的值,该变量包含了系统中可执行程序的搜索路径。
    
  2. 读取多个环境变量的值,可以使用多个环境变量名称来一次性读取它们的值。例如:
    echo $HOME $USER $SHELL
    #这将显示HOME、USER和SHELL环境变量的值。
    
  3. 查看所有环境变量,可以使用env命令。运行以下命令:
    env
    #这将列出当前所有环境变量及其对应的值。
    
  4. 查看单个环境变量的值并将其传递给其他命令,要查看HOME环境变量的值并在cd命令中使用它来切换到家目录,可以执行以下操作:
    cd $HOME
    这可以进入当前用户的home目录。
    

2.6 添加环境变量

2.6.1 系统环境相关,涉及全局的环境变量

如果你要为你的shell永久性的增加一个环境变量,比如COOL_VARIABLE,变量值为/home,你都会进行哪些操作?可以用linux命令辅以描述进行回答。

要在Linux系统上添加环境变量,需要编辑shell配置文件,以便在每次登录或启动新终端会话时设置这些变量。在Linux中,最常见的shell配置文件是.bashrc(对于Bash shell).profile。下面是添加环境变量的一般步骤:

  1. 打开终端。
  2. 使用文本编辑器vim打开shell配置文件。根据使用的shell和系统配置文件的不同,可以执行以下操作之一:
    • 对于Bash shell,打开~/.bashrc文件(如果不存在,可以创建它):
      vim ~/.bashrc
      
    • 对于Bash shell的全局配置,打开/etc/environment文件:
      sudo vim /etc/environment
      
    • 对于Bash shell的全局配置(仅适用于Debian/Ubuntu系统),可以编辑/etc/profile文件:
      sudo vim /etc/profile
      
    • 对于其他shell,例如Zsh,可以编辑其对应的配置文件,例如~/.zshrc
  3. 在打开的配置文件中,添加环境变量。例如,要添加一个名为MY_VARIABLE的环境变量,以及它的值,可以像这样添加行:
    export MY_VARIABLE="your_value_here"
    
    请确保将your_value_here替换为想要设置的实际值。
  4. 保存文件并退出文本编辑器。
  5. 在终端中重新加载配置文件,以使新的环境变量立即生效。可以运行以下命令之一:
    • 对于.bashrc或其他用户级配置文件:
      source ~/.bashrc
      
    • 对于全局配置文件(例如/etc/environment):
      source /etc/environment
      
    • 对于全局配置文件(例如/etc/profile):
      source /etc/profile
      

现在,已成功添加了一个环境变量。可以使用echo $MY_VARIABLE来验证它是否设置正确。请确保在配置文件中添加的环境变量的名称和值没有任何拼写错误。


答:一、给单个用户添加:
①:vim ~/.bash_profile
②:export COOL_VARIABLE= /home
二、给所有用户添加:
①:vim /etc/profile
②:export COOL_VARIABLE= /home

2.6.2 应用程序相关,某些程序使用的环境变量

/etc/profile.d/目录下存放的则是一些应用程序所需的启动脚本,包括颜色、语言、lessvimwhich等命令的一些附加设置。这些脚本文件之所以能够被自动执行,是因为/etc/profile中使用了for循环来调用这些脚本。因此,如果您在/etc/profile.d/路径下新建脚本,则必须遵循该脚本中定义的环境变量。

示例:

export GOROOT=/usr/local/go
export GOPATH=/opt/goprojects
export GO111MODULE=on
export GOPROXY=https://proxy.golang.com.cn,direct
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin

export PATH=/opt/bin/:$PATH

export DSMS_ENV=dev

2.6.3 /etc/profile和/etc/profile.d/的区别

  • /etc/profile文件与系统环境相关,涉及的是全局变量,修改后对所有用户生效。当一个用户登录或使用su -命令切换到另一个用户时,Login shell会运行/etc/profile脚本。一些重要的变量,如PATHUSERLOGNAME等,都是在该脚本中设置的。需要注意的是,只有Login shell启动时才会调用/etc/profile脚本,而Non-login shell则不会调用它。此外,在/home/user/.bashrc文件中设置的变量只对当前用户有用。

  • /etc/profile.d/目录下存放的则是一些应用程序所需的启动脚本,包括颜色、语言、lessvimwhich等命令的一些附加设置。这些脚本文件之所以能够被自动执行,是因为/etc/profile中使用了for循环来调用这些脚本。因此,如果您在/etc/profile.d/路径下新建脚本,则必须遵循该脚本中定义的环境变量。

除了以上内容,还需要注意以下几点

  1. /etc/profile会优先执行/etc/profile.d/目录下的所有*.sh文件。
  2. 如果要使环境变量生效,需要使用source /etc/profile./profile命令执行/etc/profile文件,并且不能使用sh /etc/profile命令,因为sh会在子shell进程中执行,导致变量无法反应到当前环境中。
  3. export相当于导出变量,使其在当前shell进程中可用。如果希望下载软件后不加入路径就能启动该程序,必须将可执行程序的路径加入PATH中。

2.7 Linux下普通文件和可执行文件有什么区别

Linux可执行文件既可以是二进制文件,也可以是普通的文本文件,关键是要有执行权限。执行权限可以简单的用命令:chmod +x 文件名 来添加执行权限。

Linux系统中,普通文件和可执行文件是两种不同类型的文件,它们有以下区别:

  1. 内容
    • 普通文件(Regular File):普通文件包含数据,可以是文本文件、二进制文件、图像文件、音频文件等。这些文件通常用于存储文本、程序代码、媒体内容等。
    • 可执行文件(Executable File):可执行文件包含可以被计算机执行的二进制代码。这些文件通常是程序、脚本或二进制可执行文件,可以被操作系统执行。
  2. 权限
    • 普通文件:普通文件可以有不同的权限,包括读取(r)、写入(w)和执行(x)权限,这些权限决定了用户对文件的操作权限。但普通文件通常不会被直接执行。
    • 可执行文件:可执行文件通常具有可执行权限(执行权限),这意味着它们可以被直接运行。要运行可执行文件,用户必须拥有执行权限,并且该文件必须具有正确的文件格式和执行入口点。
  3. 文件类型
    • 普通文件:普通文件的文件类型标识通常是-(减号),在ls -l等命令的输出中,普通文件的行以减号开头,如-rw-r–r–。
    • 可执行文件:可执行文件的文件类型标识通常是-(减号),但它们具有执行权限,允许它们在系统上执行。
  4. 用途
    • 普通文件:普通文件用于存储数据或信息,如文本、配置文件、数据文件等。它们不会被直接执行,而是由其他程序或工具处理。
    • 可执行文件:可执行文件是可以直接运行的程序或脚本。它们包含了计算机能够理解和执行的指令,可以在终端或通过其他方式运行。

普通文件和可执行文件在Linux系统中有不同的用途和特性。普通文件用于存储数据,而可执行文件用于执行计算机程序。可执行文件通常需要执行权限,以便操作系统能够运行它们。普通文件可以包含各种类型的数据,而可执行文件包含二进制代码,可以在计算机上执行。

2.8 Linux下进程间通信有几种方式

Linux系统中,有多种进程间通信(Inter-Process Communication,IPC)的方式,允许不同的进程之间进行数据交换和协作。以下是常见的Linux IPC方法:

  1. 管道(Pipe)
    • 匿名管道:通过使用|操作符,可以将一个进程的标准输出连接到另一个进程的标准输入。这种方式适用于有父子关系的进程或者同时由一个外壳控制的进程。
    • 命名管道(FIFO):通过创建命名管道文件,多个进程可以使用该文件来进行通信。它们不需要共享父进程或同一个终端。
  2. 消息队列(Message Queue)
    • 进程可以通过消息队列发送和接收消息。消息队列通常用于进程之间的异步通信,允许进程按顺序处理消息。
  3. 信号(Signal)
    • 信号是Linux中用于通知进程发生事件的一种机制。进程可以发送信号给其他进程,例如SIGTERM用于请求进程终止。信号可用于实现基本的进程间通信。
  4. 共享内存(Shared Memory)
    • 进程可以创建一个共享内存区域,多个进程可以将其映射到它们的地址空间,并直接读取或写入共享内存。这是一种高效的IPC方法,但需要处理同步和互斥问题。
  5. 信号量(Semaphore)
    • 信号量是用于同步进程的计数器。它们可以用来控制多个进程对共享资源的访问,以避免竞争条件。
  6. 套接字(Socket)
    • 套接字通常用于不同主机上的进程间通信,但也可用于同一主机上的进程通信。它们通常与网络编程相关,可以在不同计算机之间或同一计算机上的不同进程之间传递数据。
  7. 文件锁(File Locking)
    • 进程可以使用文件锁来协调对共享文件的访问。通过文件锁,进程可以锁定文件的某部分以防止其他进程同时修改。
  8. 信号文件(Signal File)
    • 进程可以创建信号文件,当其他进程检测到该文件存在时,它们可以进行相应的操作。这是一种简单的IPC方法。

每种IPC方式都有其适用的场景和特点。选择正确的IPC方法取决于应用程序需求和设计。不同的IPC方式具有不同的复杂性和性能特点,因此需要谨慎选择以确保进程间的协作和数据交换得以顺利进行。

2.9 Linux下僵尸进程和孤儿进程是怎么产生的

Linux下,僵尸进程和孤儿进程是由于进程的父子关系和进程的终止行为引起的。下面我将解释它们是如何产生的:

  1. 僵尸进程(Zombie Processes):僵尸进程是指已经终止但其父进程尚未调用wait()waitpid()等系统调用来获取子进程的退出状态信息的进程。当一个子进程终止时,它会向父进程发送一个终止信号(SIGCHLD),父进程通常应该使用wait()waitpid()来等待子进程的终止状态。如果父进程没有处理子进程的终止状态,子进程就会变成僵尸进程。

僵尸进程的产生过程:

  • 子进程创建并开始执行。
  • 子进程在某个时刻终止,并向父进程发送终止信号。
  • 父进程未及时调用wait()waitpid()来处理子进程的终止状态。
  • 子进程的终止状态信息保留在系统中,形成僵尸进程。

解决僵尸进程问题的方法是,父进程应该定期调用wait()waitpid()来回收子进程的资源和终止状态。

  1. 孤儿进程(Orphan Processes):孤儿进程是指父进程在子进程终止之前就终止了,导致子进程的父进程变为init进程(通常进程ID为1)。init进程会负责回收孤儿进程并释放它们占用的系统资源。

孤儿进程的产生过程:

  • 父进程创建子进程。
  • 父进程在子进程终止之前终止。
  • 子进程继续运行,但其新的父进程变为init进程。

孤儿进程通常不会导致资源泄漏或问题,因为它们最终会被init进程回收。然而,这种情况可能需要注意,因为孤儿进程在终止之前可能会执行一些操作。

总结:
僵尸进程是由于父进程未能正确处理子进程的终止状态而产生的,而孤儿进程是由于父进程在子进程终止之前终止而产生的。在编写和管理进程的代码时,应注意处理这两种情况,以确保系统资源得到正确回收。


参考1:Linux操作系统之孤儿进程和僵尸进程

僵尸进程:

当一个进程调用 exit 命令结束自己的生命时,其实它并没有真正的被销毁,内核只是释放了该进程的所有资源,包括打开的文件、占用的内存等,但是留下一个称为僵尸进程的数据结构,这个结构保留了一定的信息(包括进程号 the process ID,退出状态,运行时间),这些信息直到父进程通过 wait()/waitpid() 才能释放。

但如果父进程没有这么做的话,此时,子进程虽然已经退出了,但是在系统进程表中还为它保留了一些退出状态的信息,如果父进程一直不取得这些退出信息的话,这系统进程表就将一直被占用,此时,这些占着茅坑不拉屎的子进程就成为“僵尸进程”。

孤儿进程:

父进程先于子进程结束,则子进程成为孤儿进程,子进程的父进程成为 init进程,称为 init 进程领养孤儿进程。

2.10 Linux在使用TOP看CPU时负载和使用率有什么区别

参考1:Linux中 cpu负载和cpu利用率的区别

CPU负载和CPU利用率的区别
CPU利用率:显示的是程序在运行期间实时占用的CPU百分比。top命令中,CPU使用率由"us"(用户空间)和"sy"(系统内核空间)等字段表示,它们分别表示用户进程和系统内核的CPU使用率。

  • "us"表示用户空间的CPU使用率,即由用户进程消耗的CPU时间。
  • "sy"表示系统内核空间的CPU使用率,即由操作系统内核消耗的CPU时间。
  • "ni"表示用户进程的低优先级CPU使用率。
  • "id"表示CPU处于空闲状态的时间比例。
  • "wa"表示CPU等待I/O操作完成的时间比例。
  • "st"表示虚拟化环境中被虚拟机监控程序(hypervisor)"偷取"的时间比例。

高的CPU使用率可能表明系统的CPU资源正在被密集使用,这可能是由于运行大量计算密集型进程或I/O密集型操作。


CPU负载:显示的是一段时间内正在使用和等待使用CPU的平均任务数。通常以三个数字表示,分别对应于过去1分钟、5分钟和15分钟的时间段。负载的含义是等待运行的进程数,包括正在运行和等待CPU时间片的进程。负载的理想值取决于系统的核数,一般来说,负载应该低于系统的核数,以确保系统运行顺畅。

  • 如果负载是1.0,表示系统上有一个进程正在运行,而其他进程正在等待。
  • 如果负载是2.0,表示系统上有两个进程正在运行,而其他进程正在等待。
  • 如果负载是0.5,表示系统上有一个进程正在运行,而另一个进程正在等待。

较高的负载可能表明系统过载,需要进一步分析,找出导致负载升高的原因。这可能包括CPU密集型任务、I/O等待等。

总结:
负载和CPU使用率是两个不同的性能指标,用于分别表示系统中等待运行的进程数量和CPU资源的利用情况。可以根据具体的性能问题来分析这两个指标,以了解系统的工作情况和性能瓶颈。

2.11 Linux查看网络带宽的命令

要在Linux中查看网络带宽使用情况,可以使用一些常见的命令工具来监视网络流量。以下是一些常用的命令:

  1. iftopiftop是一个交互式的实时流量监视器,它可以显示每个网络连接的带宽使用情况,以及流量的方向和速度。
    • 安装iftop(如果尚未安装)
    sudo apt-get install iftop   # 对于 Debian/Ubuntu
    sudo yum install iftop       # 对于 CentOS/RHEL
    
    • 运行iftop
    sudo iftop
    
  2. nloadnload是一个简单的命令行工具,用于显示网络流量的实时图形化视图。
    • 安装nload(如果尚未安装)
    sudo apt-get install nload   # 对于 Debian/Ubuntu
    sudo yum install nload       # 对于 CentOS/RHEL
    
    • 运行nload
    nload
    
  3. iftopnload都是交互式的工具,可以在终端中实时查看网络带宽使用情况。要退出这些工具,通常可以按下 Ctrl+C。
  4. iperfiperf是一个网络性能测试工具,可以用来测量网络带宽和性能。可以在两台计算机之间运行服务器端和客户端,以测量它们之间的带宽。
    • 安装iperf(如果尚未安装)
    sudo apt-get install iperf   # 对于 Debian/Ubuntu
    sudo yum install iperf       # 对于 CentOS/RHEL
    
    • 运行iperf服务器端(在一台计算机上)
    iperf -s
    
    • 运行iperf客户端(在另一台计算机上,替换为服务器的 IP 地址)
    iperf -c <server_ip>
    
  5. sarsar命令(System Activity Reporter)可以用于收集和报告系统的各种性能指标,包括网络带宽使用情况。
    • 安装sar(如果尚未安装)
    sudo apt-get install sysstat   # 对于 Debian/Ubuntu
    sudo yum install sysstat       # 对于 CentOS/RHEL
    
    • 运行sar来查看网络带宽使用情况
    sar -n DEV 1
    
    上述命令中的-n DEV选项用于显示网络接口的统计信息,1表示每秒更新一次。

请根据需求选择适当的工具来监视网络带宽使用情况。这些工具可以帮助实时跟踪网络流量,了解网络性能并排查潜在的问题。

2.12 Linux软连接和硬连接的区别

Linux系统中,有两种主要的文件链接类型:软连接(Symbolic Link,也称为符号链接)硬连接(Hard Link)。它们都用于创建文件之间的关联,但它们之间存在一些关键差异。

  • 软连接是一个独立的文件,指向另一个文件或目录的路径。它可以跨越文件系统和指向不存在的目标,但它更脆弱,因为目标被删除或移动后,它会变成坏链接。
  • 硬链接是源文件的副本,与原始文件共享相同的inode。它只能在同一文件系统上创建,不可以指向目录,但当原始文件被删除后,硬链接仍然保留数据。

软连接(Symbolic Link):

  1. 特点
    • 软连接是一个特殊的文件,它包含了指向另一个文件或目录的路径。
    • 它可以跨越不同的文件系统,甚至可以指向不存在的目标。
    • 软连接可以指向文件或目录。
  2. 创建方式:使用ln -s命令创建软连接。
    ln -s /path/to/target /path/to/symlink
    
  3. 修改源文件或目录:如果原始文件或目录被删除或移动,软连接仍然存在,但它将变为坏链接(dangling link)
  4. 权限:软连接有自己的权限和所有者,但实际上它是一个指向目标的路径,因此权限检查是针对目标而不是软连接本身的。
  5. 示例
    ln -s /usr/bin/python3 /usr/local/bin/python
    

硬连接(Hard Link):

  1. 特点
    • 硬链接是目标文件或目录的一个副本,它与原始文件有相同的inode号。
    • 硬链接只能在同一个文件系统中创建,且不能指向目录。
    • 当删除原始文件时,硬链接仍然可以访问数据,因为它们共享相同的inode
  2. 创建方式:使用ln命令创建硬链接。
    ln /path/to/target /path/to/hardlink
    
  3. 修改源文件:所有硬链接都与源文件共享相同的数据和元数据,因此修改一个硬链接将影响其他硬链接以及源文件本身。
  4. 权限:硬链接不具有自己的权限和所有者。权限检查仍然是基于文件本身。
  5. 示例
    ln /etc/fstab /tmp/fstab-hardlink
    

2.13 Linux中TCP的配置参数有哪些

参考1:linux下如何配置TCP参数设置详解

  1. TCP最大连接数(net.core.somaxconn)
    • 描述:这个参数定义了处于半连接状态(SYN_RCVD)的最大连接请求队列的大小。
    • 默认值:128
  2. TCP最大挂起连接数(net.ipv4.tcp_max_syn_backlog)
    • 描述:定义了半连接状态(SYN_RCVD)的最大挂起连接数,即等待accept()的连接队列的大小。
    • 默认值:1024
  3. TCP连接超时时间(net.ipv4.tcp_synack_retries)
    • 描述:定义了TCP连接建立的最大尝试次数,通常在SYN-ACK重传方面使用。
    • 默认值:5
  4. TCP最大窗口尺寸(net.ipv4.tcp_window_scaling)
    • 描述:启用TCP窗口自动缩放,允许更大的TCP窗口尺寸,以提高网络性能。
    • 默认值:1(开启)
  5. TCP最大接收窗口尺寸(net.core.rmem_max)
    • 描述:定义了TCP接收缓冲区的最大尺寸。
    • 默认值:默认取决于系统版本和配置。
  6. TCP最大发送窗口尺寸(net.core.wmem_max)
    • 描述:定义了TCP发送缓冲区的最大尺寸。
    • 默认值:默认取决于系统版本和配置。
  7. TCP延迟确认时间(net.ipv4.tcp_delack_min)
    • 描述:定义了TCP延迟确认(Delayed ACK)的最小延迟时间。
    • 默认值:40(毫秒)
  8. TCP最大连接数限制(net.core.netdev_max_backlog)
    • 描述:定义了在接口上排队等待处理的入站数据包的最大数量。
    • 默认值:1000
  9. TCP保持连接超时时间(net.ipv4.tcp_keepalive_time)
    • 描述:定义了TCP连接保持活跃的时间间隔。
    • 默认值:7200秒(2小时)
  10. TCP重传超时时间(net.ipv4.tcp_retries2)
    • 描述:定义了TCP连接中的重传尝试次数。
    • 默认值:15

这些参数可以通过在/etc/sysctl.conf或相关的配置文件中进行设置,并通过sysctl工具来加载或重新加载。例如,要永久更改参数,可以编辑/etc/sysctl.conf文件,然后运行sysctl -p以应用新的配置。

注意,在调整这些参数时,需要谨慎,以避免对系统性能和稳定性产生不利影响。建议在调整参数之前详细了解它们的含义和影响,并在生产环境中小心测试。

2.14 Linux查看当前连接服务器的前10位Ip

要查看当前连接到服务器的前10位IP地址,可以使用以下命令结合一些其他命令来实现。这里使用netstatawk命令来实现:

netstat -tn 2>/dev/null | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -nr | head -n 10

命令的各个部分:

  1. netstat -tn 2>/dev/null:这部分命令用于列出当前网络连接。-t选项表示只显示TCP连接,-n选项表示以数字形式显示IP地址和端口号,2>/dev/null用于将错误信息重定向到空设备,以避免显示不必要的错误信息。
  2. awk '{print $5}':这将提取netstat输出的第5列,即远程IP地址和端口。
  3. cut -d: -f1:这将从IP地址和端口中提取IP地址部分,因为我们只关心IP地址。
  4. sort:这将对IP地址进行排序。
  5. uniq -c:这将统计每个IP地址的出现次数,并在前面显示出现次数。
  6. sort -nr:这将按逆序(从最多到最少)对IP地址按出现次数排序。
  7. head -n 10:最后,这将显示前10个IP地址,这些地址最频繁地连接到服务器。

执行这个命令后,将看到列出了前10个最频繁连接到服务器的IP地址。请注意,这些IP地址可能是服务器上不同的客户端或服务的地址。

2.15 Linux理论上最多能开多少个端口?

Linux系统中,理论上最多可以打开的端口数是65535,这是因为TCPUDP协议的端口号范围是0到65535(2^16 - 1)。这范围中的0到1023端口号通常被称为"系统端口",用于标准协议和服务(如HTTP的80端口、SSH的22端口等),而范围中的1024到65535端口号通常被称为"动态端口",用于应用程序和临时网络连接。

然而,实际上,不同的Linux系统可能会有一些限制,导致不能实际上打开这么多端口。这些限制包括:

  1. 可用端口范围:有些Linux系统可能限制了可以使用的端口范围,尤其是在低端口号上,以确保系统服务的正常运行。
  2. 系统资源:打开大量端口需要占用系统资源,如文件描述符(file descriptors),因此操作系统可能会限制每个进程可以打开的文件描述符数量。
  3. 网络硬件和性能:实际的网络硬件和性能也可能成为限制因素,因为大量并发的网络连接可能会影响网络性能。

通常情况下,不需要打开太多端口。如果需要处理大量并发连接,可以使用高级的网络编程技术,如使用多线程、多进程或事件驱动的服务器来有效地管理连接。此外,一些负载均衡和反向代理解决方案也可以帮助分散流量,减轻单一服务器上的连接负担。

2.16 假如服务器有瓶颈,你一般看哪些指标?你通过什么命令去看看哪些指标?

当服务器出现性能瓶颈时,通常需要监视各种系统性能指标,以帮助定位问题并找出潜在的瓶颈原因。以下是一些常见的性能指标和相应的Linux命令,用于查看这些指标:

  1. CPU利用率
    • 查看整体CPU利用率:tophtop
    • 查看每个CPU核心的利用率:mpstat -P ALL 1top 中按1键
  2. 内存利用率
    • 查看内存使用情况:free -m
    • 查看内存详细信息:tophtop
  3. 磁盘使用情况
    • 查看磁盘空间:df -h
    • 查看每个磁盘分区的I/O统计:iostat -dx 1
  4. 网络状况
    • 查看网络接口的统计信息:ifconfigip -s link
    • 查看网络连接状态:netstat -tulnss -tuln
  5. 进程和负载
    • 查看运行中的进程:ps auxtop
    • 查看系统负载:uptime
  6. 日志文件
    • 查看系统日志:cat /var/log/syslog 或 cat /var/log/messages
    • 查看应用程序日志:根据应用程序的日志文件位置,通常在/var/log目录下。

通过监视这些指标,您可以获得关于服务器性能的详细信息,从而识别潜在的瓶颈。一般来说,高CPU利用率可能表示CPU瓶颈,高内存利用率可能表示内存瓶颈,高磁盘I/O可能表示磁盘瓶颈,高网络流量可能表示网络瓶颈。

针对特定问题,还可以使用其他专门的工具和命令来进行深入的性能分析,如stracevmstatiotopnetstatsar 等。不同的性能问题可能需要不同的工具和方法来诊断和解决。

2.17 Linux下使用free查看内存,这个可用内存是怎么看的?真正可用的内存是有哪些?

Linux系统中,free命令用于查看内存使用情况,其中的"可用内存"并不总是直观理解的,因为它会考虑操作系统的内存管理策略。可用内存不仅包括空闲的物理内存,还包括操作系统使用的内存中的可回收部分。
free命令的输出通常如下所示:

              total        used        free      shared  buff/cache   available
Mem:       16336232     4394884     5297220      618156     6642128    10956416
Swap:             0           0           0

其中,"available"行的数值表示当前系统的可用内存。
"可用内存"包括以下几个部分:

  1. “free”:表示完全未使用的物理内存。
  2. “buff/cache”:表示操作系统使用的内存中,可以被回收的部分,包括磁盘缓存(buffer)和页面缓存(cache)。这些内存可以在需要时迅速释放,以供应用程序使用。
  3. “used”:表示操作系统当前使用的内存总量。
  4. “shared”:表示被共享的内存,通常由共享库等共享资源使用。
  5. “available”:表示可供应用程序使用的内存,包括未使用的内存、缓存和共享内存。这是当前系统中可以分配给新进程的内存数量。

在实际使用中,"available"行的数值更接近于实际可用内存。如果您需要获取精确的可用内存信息,可以使用Linux系统的 /proc/meminfo文件,或者借助其他工具如 htoptop 来查看更详细的内存使用情况。

注意Linux内存管理是动态的,因此内存的可用性会根据系统的工作负载和内存管理策略而变化。在大多数情况下,Linux会尽力充分利用可用内存来提高性能,将不再需要的内存用于缓存,以减少磁盘I/O等。这种内存管理策略可以提高系统性能,但可能会导致"可用内存"的数值看似较低。

2.18 用没有用过Linux作为路由器使用?

Linux系统上,可以将其配置为路由器以用于网络数据包转发和路由功能。以下是一些步骤来将Linux系统配置为路由器:

  1. 启用IP转发:首先,需要确保Linux系统上的IP转发功能已经启用。可以通过修改内核参数来实现:
sudo sysctl -w net.ipv4.ip_forward=1

这将启用IPv4数据包转发功能。如果需要IPv6支持,可以使用类似的命令来启用IPv6数据包转发。
2. 配置网络接口:配置Linux系统上的网络接口,确保每个接口都有正确的IP地址和子网掩码。可以使用ifconfigip命令来配置网络接口。例如:

sudo ifconfig eth0 192.168.1.1 netmask 255.255.255.0

这将配置eth0接口的IP地址为192.168.1.1,子网掩码为255.255.255.0。可以根据网络拓扑和需求配置其他接口。
3. 配置静态路由或使用动态路由协议:如果需要将数据包从一个网络转发到另一个网络,需要配置静态路由规则或使用动态路由协议(如BGP、OSPF、RIP)来管理路由表。可以使用ip route命令来配置静态路由。

sudo ip route add 10.0.0.0/24 via 192.168.1.2 dev eth0

这将添加一个静态路由,将数据包目的地为10.0.0.0/24的数据包发送到192.168.1.2的网关,通过eth0接口进行转发。
4. 配置NAT(Network Address Translation):如果要将内部网络连接到公共互联网,通常需要配置NAT,以便将内部IP地址映射到一个公共IP地址。可以使用iptables来配置NAT规则。

sudo iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADE

这将配置NAT规则,允许数据包从eth1接口出口并将源IP地址替换为该接口的IP地址,以实现Internet访问。
5. 防火墙设置:配置适当的防火墙规则以保护你的路由器和网络。使用iptables或其他防火墙工具来配置入站和出站规则,确保只有授权的流量可以通过。

这些步骤是将Linux系统配置为路由器的基本步骤。具体的配置可能会根据网络拓扑和需求而有所不同。确保在进行配置时谨慎操作,并考虑网络安全和性能方面的需求。

2.19 你对Linux系统的node指标的理解是怎么样的?比如负载。(待进一步验证)

负载的话,看三个指标吧,一个是这个CPU,然后还有就是内存,最后就是这个它的这个硬磁盘的使用情况,然后这三方面来看,然后还有的话,如果可能就是这个网络情况吧,是这样。

2.20 这个node的值它一般到多大是算高?需要介入排查呢?

2.21 系统指标采集,比如你需要你用go写一个agent,采集agent,那采集这些系统指标的一般的实现方法大概有哪些?(待进一步验证)

采集CPU、内存、硬盘、网络,然后还有程序的运行数量。

2.22 你怎么用go代码去拿这些数据呢?(待进一步验证)

go 的话它里面它有一个包是OS,它这个里面的话主要是与系统相关的,应该可以通过这个包里面的一些方法来获取到这个系统服务器上面的一些参数。

2.23 在linux服务器上的话一般是用什么命令要看日志?

  1. 查看系统日志:使用journalctl命令可以查看systemd日志。这个命令提供了很多选项,可以用于筛选和查找特定的日志信息。
    journalctl
    
  2. 查看特定日志文件:使用cat、tail、less等命令可以查看特定日志文件的内容。例如,查看/var/log/syslog文件的最后几行:
    tail /var/log/syslog
    
  3. 查看实时日志:使用tail命令的-f选项可以实时查看日志文件的新增内容,有助于实时监控系统状态。
    tail -f /var/log/syslog
    
  4. 查看指定服务的日志:使用journalctl命令,结合-u选项可以查看特定服务的日志。例如,查看SSH服务的日志:
    journalctl -u ssh
    
  5. 查看错误日志:使用dmesg命令可以查看内核环缓冲区的内容,显示系统启动过程中的消息和错误信息。
    dmesg
    
  6. 查看登录信息:使用last命令可以查看登录历史记录,显示系统上的用户登录信息。
    last
    
  7. 查看用户活动日志:使用w或who命令可以查看当前登录用户的活动。
    w
    
  8. 查看应用程序日志:不同的应用程序可能会将日志存储在不同的位置。通常,应用程序的日志会存储在/var/log目录下,具体位置和命名可能会因发行版和应用程序而有所不同。

这些命令和工具提供了一些基本的日志查看和分析功能。在实际应用中,可以根据具体的需求使用其他工具和技术,如grep、awk、sed等,以及日志分析工具如 Logrotate、ELK Stack等。

2.24 每周定时备份一下MySQL的一个数据库,shell脚本该怎么写。

#!/bin/bash

# MySQL 连接信息
DB_HOST="localhost"
DB_USER="your_username"
DB_PASS="your_password"
DB_NAME="your_database"

# 备份存储路径
BACKUP_DIR="/path/to/backup"

# 当前日期作为备份文件名前缀
DATE_PREFIX=$(date +%Y%m%d)

# 创建备份目录
mkdir -p $BACKUP_DIR

# 完整备份文件名
BACKUP_FILE="$BACKUP_DIR/$DATE_PREFIX-$DB_NAME.sql"

# 使用 mysqldump 导出数据库
mysqldump -h $DB_HOST -u $DB_USER -p$DB_PASS $DB_NAME > $BACKUP_FILE

# 检查备份是否成功
if [ $? -eq 0 ]; then
    echo "MySQL backup completed successfully: $BACKUP_FILE"
else
    echo "Error: MySQL backup failed!"
fi

脚本的说明:

  1. 修改DB_HOST、DB_USER、DB_PASS、DB_NAME分别为你的MySQL主机、用户名、密码、以及要备份的数据库名称。
  2. 修改BACKUP_DIR为你希望存储备份文件的目录。
  3. 使用date命令生成当前日期作为备份文件名的前缀。
  4. 使用mysqldump命令导出MySQL数据库到指定的备份文件中。
  5. 在脚本中使用条件语句检查导出过程是否成功,输出相应的信息。

请确保你在脚本中妥善处理数据库连接信息,以确保安全性。你可能需要设置脚本的执行权限,并使用cron作业调度工具来定期执行脚本。例如,将以下内容添加到你的 crontab文件中,以每周日的凌晨3点执行备份:

0 3 * * 0 /path/to/your/script.sh

这表示在每周日的凌晨 3 点执行指定的脚本。根据实际情况调整路径和时间。

3 Docker

Docker是一个用于开发、运输和运行容器化应用程序的平台。容器是轻量级、独立和可执行的软件包,包括运行一个软件所需的一切,包括代码、运行时、系统工具、库和设置。Docker因其简化创建、部署和管理应用程序的过程而在软件开发和部署领域广受欢迎。

3.1 Docker特点 / 优势

  1. 轻量级容器Docker容器非常轻量,因此可以在几秒钟内启动和停止。与传统虚拟化相比,它们消耗更少的资源,因此可以在同一物理主机上运行多个容器。
  2. 一致性Docker容器包含了应用程序及其所有依赖项,包括库、运行时和配置文件。这确保了在不同环境中容器的一致性,从而减少了“在我的机器上可以工作”的问题。
  3. 可移植性Docker容器可以在不同的环境中运行,无论是开发、测试、生产服务器还是云计算平台,都可以保持一致。这使得应用程序更容易迁移到不同的部署环境。
  4. 快速部署:由于容器可以快速启动,因此应用程序可以更快地部署和扩展。这对于需要快速响应用户需求的情况非常有用。
  5. 隔离性Docker容器提供了高度的隔离,使应用程序之间和与主机系统之间保持独立。这意味着一个容器的问题不会影响其他容器或主机系统。
  6. 版本控制和镜像管理Docker允许创建和管理容器镜像,这些镜像可以与其他开发人员和团队共享。可以使用Docker Hub或自己的私有注册表来存储和分享镜像。
  7. 易于扩展Docker容器可以根据需要水平扩展,以满足流量和资源需求的增加。容器编排工具如KubernetesDocker Swarm可以帮助自动化和管理扩展过程。
  8. 生态系统Docker拥有庞大的生态系统,有丰富的第三方工具和服务,可以扩展Docker的功能,例如监控、日志记录、安全性、网络等方面。
  9. 开源和社区支持Docker是一个开源项目,拥有活跃的社区支持。这意味着有大量的文档、教程和社区贡献的工具和插件可供使用。
  10. 多平台支持Docker不仅限于Docker,还支持WindowsmacOS等操作系统,因此可以在多个操作系统上使用相同的Docker容器。

总的来说,Docker的特点包括高度的可移植性、一致性、隔离性和快速部署,使其成为开发人员和运维团队的有力工具,用于构建、交付和管理现代应用程序。

3.2 Docker架构

Docker的架构是一个分层的体系结构,它包括多个组件,每个组件都有特定的功能。以下是Docker的主要架构组件:

  1. Docker守护程序(Docker Daemon)Docker守护程序是Docker的后台服务,负责管理Docker容器的生命周期。它接收来自Docker客户端的命令,并与容器运行时交互来创建、启动、停止和删除容器。Docker守护程序还管理镜像、网络、存储和卷等资源。
  2. Docker客户端Docker客户端是与用户交互的命令行工具或API客户端。用户可以使用Docker客户端通过命令行界面或APIDocker守护程序通信,以执行各种Docker操作。
  3. Docker镜像(Docker Images)Docker镜像是容器的只读模板,包含了运行容器所需的文件系统、应用程序代码、运行时、系统工具、库和配置。镜像可以被用来创建多个容器实例。Docker镜像采用分层存储,这意味着它们可以共享相同的基础层,从而节省存储空间。
  4. Docker容器(Docker Containers)Docker容器是Docker镜像的可运行实例。容器包括应用程序及其依赖项,并在隔离的环境中运行。容器是轻量级、可移植的,并且可以在不同的主机上运行,而不受主机操作系统的影响。
  5. Docker仓库(Docker Registry)Docker仓库是用于存储和分享Docker镜像的中央位置。Docker Hub是一个公共Docker仓库,开发人员可以在其中找到和分享镜像。还可以设置自己的私有Docker仓库。
  6. Docker ComposeDocker Compose是一个用于定义和运行多容器Docker应用程序的工具。它使用YAML文件来描述应用程序的服务、网络、卷等配置,可以简化复杂应用程序堆栈的管理。
  7. Docker网络Docker提供多种网络模式,允许容器之间进行通信,以及容器与外部网络的连接。这包括桥接网络、主机网络、覆盖网络等。
  8. Docker存储Docker容器可以访问持久化存储,包括卷(volumes)和绑定挂载(bind mounts)。这允许容器在运行时持久化保存数据,并与主机文件系统交互。
  9. Docker编排工具Docker提供编排工具,如Docker SwarmKubernetes,用于自动化和管理多个容器的部署、伸缩和编排。

Docker的架构允许开发人员和运维人员轻松创建、交付和运行容器化应用程序,实现了应用程序的一致性、可移植性和隔离性。容器技术已经成为现代软件开发和部署的重要组成部分,为应用程序开发和部署带来了更高的效率和可靠性。
Linux、Docer、K8S相关面试题及解答_第1张图片

3.3 Docker底层原理

Docker的底层原理涉及多个关键技术和组件,包括Linux容器、cgroups、命名空间、联合文件系统以及Docker自身的架构。以下是Docker底层原理的关键要点:

  1. Linux容器(Linux Containers,LXC)Docker基于Linux容器技术,这是Linux内核提供的一种虚拟化技术。容器允许将一个应用程序及其依赖项隔离到一个独立的用户空间中,但与宿主操作系统共享内核资源。这种隔离性使容器可以在不同的环境中运行,同时具有较低的资源开销。
  2. 命名空间(Namespaces):命名空间是Linux内核提供的一种机制,用于隔离不同进程之间的资源。Docker使用不同类型的命名空间来隔离进程的文件系统、网络、进程、用户等方面的视图,从而实现容器的隔离。
  3. cgroups(Control Groups)cgroupsLinux内核的特性,用于限制和管理资源的使用,如CPU、内存、磁盘I/O等。Docker使用cgroups来确保容器不会耗尽主机的资源,并允许对容器资源分配进行精细化控制。
  4. 联合文件系统(Union File System):联合文件系统是一种文件系统层叠技术,允许将多个文件系统层合并为一个单一的文件系统视图。Docker使用联合文件系统来构建镜像,其中包含基础镜像和一系列文件系统层,使镜像变得轻量且易于共享和管理。
  5. Docker镜像Docker镜像是只读的、多层的文件系统,它包含了应用程序代码、运行时、系统工具、库和配置。每一层都可以被重新使用,这使得镜像变得高效且易于构建。容器实例基于这些镜像运行,并添加一个可写层用于容器特定的修改。
  6. Docker守护程序和客户端Docker的架构包括一个守护程序(Docker Daemon)和一个客户端(Docker Client)。守护程序负责管理容器的生命周期和资源,而客户端允许用户与守护程序交互,以执行各种Docker操作。
  7. Docker网络Docker提供了不同类型的网络模式,如桥接网络、主机网络和覆盖网络,以便容器之间通信以及与外部网络连接。这些网络模式使用Linux内核的网络命名空间来实现隔离。
  8. Docker存储Docker容器可以使用持久化存储,包括卷(volumes)和绑定挂载(bind mounts),以便在容器之间或与主机文件系统之间共享数据。

总结:
Docker的底层原理涉及了多个Linux内核功能的协同工作,以实现容器的隔离、资源管理和文件系统层叠。这些技术共同构成了Docker的核心,使其成为一种强大的容器化解决方案,可用于构建、交付和管理应用程序。理解这些原理有助于更深入地使用和调优Docker容器。

3.4 Docker镜像分层

参考1:https://zhuanlan.zhihu.com/p/139653646

docker中的镜像是按照分层的结构一层一层网上叠加的。每层代表Dockerfile中的一条指令。

以下面Dockerfile为例:
FROM ubuntu:18.04
COPY . /app
RUN make /app
CMD python /app/app.py

采用镜像分层的方式最好的就是共享资源,假设有多个镜像都是从相同的底层镜像构建来的,那么docker 只需要在磁盘上保持一份底层镜像,同时内存只用加载一份底层镜像,这样一来这一份镜像就可以为其他的镜像服务了。

容器和镜像区别:

对于容器和镜像(container和image)的主要区别就是顶部的可写层(the top writable layer),在容器中添加数据或者修改现有数据的所有读写操作都会存储在此可写层中。删除容器后,可写层也会被删除,而基础镜像则保持不变。
每个容器都会有自己的可写层,所有的改变都存储在该容器层中。多个容器可以共享对同一基础镜像的访问,但可以拥有自己的数据状态。


Docker镜像采用分层存储(Layered File System)的方式来构建,这个特性是Docker镜像的核心概念之一。镜像的分层结构使得镜像的创建、共享和管理变得高效。下面是有关Docker镜像分层的关键信息:

  1. 分层文件系统Docker镜像使用分层文件系统来构建。每个镜像可以由多个文件系统层组成,每一层都是只读的,并且包含了文件和目录。这些层以一种特殊的方式叠加在一起,形成了一个完整的镜像。
  2. 基础镜像(Base Image):镜像的最底层通常是一个基础镜像,它包含了操作系统的根文件系统和一些最基本的工具。基础镜像通常是一个标准的Linux发行版,如UbuntuAlpineCentOS
  3. 镜像层:在基础镜像之上,每个Docker镜像可以包含一个或多个镜像层。每个镜像层都添加了一些文件、目录或配置。这些镜像层可以在不同的镜像之间共享,从而节省存储空间。
  4. 只读和可写层:镜像的所有层都是只读的,这意味着它们不可更改。当容器运行时,Docker会在顶部添加一个可写的层,用于存储容器运行时的修改。这个可写层通常被称为"容器层"或"容器文件系统",并且是唯一可写的部分。
  5. 分层的好处:镜像的分层结构具有以下好处:
    • 高效存储和传输:因为镜像层可以在不同的镜像之间共享,所以它们不会被多次存储或传输,节省了存储空间和带宽。
    • 可复用性:通过分层,镜像可以重复使用基础层,从而降低了创建新镜像的成本。
    • 版本控制:每个镜像层都有一个唯一的哈希值,这使得镜像版本的管理更容易,以确保镜像的一致性和可重复性。
  6. Docker镜像命令: 使用Docker镜像命令(如docker pulldocker builddocker push)可以方便地获取、构建和共享镜像。当构建或拉取一个镜像时,Docker会下载或创建所需的镜像层,并按顺序叠加它们以构建完整的镜像。

总结:
Docker镜像分层是一种高效的方式来管理和共享容器化应用程序的组件。它使得镜像的创建、更新和传输变得更加高效和可维护。通过共享基础层和分层结构,Docker镜像允许在不同环境中实现一致性和可移植性。

3.5 Docker Dockfile

Dockerfile(中文称为“Docker文件”)是一个文本文件,用于定义构建Docker容器镜像的一组指令。Docker容器是轻量、可移植且隔离的环境,可以在不同系统上一致地运行应用程序和服务。DockerfileDocker生态系统的基本组成部分,因为它们提供了创建定制容器镜像的方式,以满足特定需求。

Dockerfile结构的概述以及每个部分的作用:

  1. 基础镜像Dockerfile中的第一行指定了用于构建自定义镜像的基础镜像。可以将基础镜像视为应用程序的起点。例如,可以使用官方的Linux发行版镜像,如Ubuntu、轻量的Alpine Linux镜像,或针对特定编程语言或框架定制的镜像。
    FROM ubuntu:20.04
    
  2. 环境设置:在定义基础镜像之后,可以设置应用程序的环境。这包括安装依赖项、设置环境变量和根据需要配置系统。
    RUN apt-get update && \
        apt-get install -y python3
    
  3. 复制文件:可以将本地计算机上的文件复制到容器镜像中。这通常用于添加应用程序代码、配置文件和其他资源。
    COPY ./app /app
    
  4. 工作目录:设置容器内的工作目录,后续命令将在其中执行。这有助于组织应用程序的文件结构。
    WORKDIR /app
    
  5. 暴露端口:如果应用程序监听特定网络端口,可以在Dockerfile中暴露这些端口。
    EXPOSE 80
    
  6. 命令:最后,指定容器启动时应执行的命令。这可以是简单的shell命令、脚本或应用程序入口点。
    CMD ["python3", "app.py"]
    

构建了Dockerfile之后,可以使用docker build命令来从中构建镜像。例如:

docker build -t my-custom-image:1.0 .

这个命令告诉Docker使用当前目录中的 Dockerfile(.)来构建一个镜像,并将其标记为my-custom-image,版本为1.0

构建镜像后,可以使用docker run来创建和运行基于该镜像的容器:

docker run -p 8080:80 my-custom-image:1.0

这将从my-custom-image:1.0 镜像创建一个容器,并将容器内部的端口80映射到主机系统上的端口8080。

Dockerfile允许以版本控制的方式定义应用程序的环境和依赖关系,从而更容易在不同环境和平台上共享和部署应用程序。

3.5.1 Docker Dockfile完整示例

# 使用官方的 Golang 镜像作为基础镜像,选择需要的 Go 版本
FROM golang:1.17

# 设置容器内的工作目录
WORKDIR /app

# 将本地的 Go 源代码复制到容器中
COPY . .

# 构建 Go 应用程序
RUN go build -o myapp

# 暴露容器内的端口,此示例服务使用 8080 端口
EXPOSE 8080

# 定义容器启动时执行的命令
CMD ["./myapp"]

这个示例Dockerfile基于官方Golang镜像构建了一个容器镜像,执行以下操作:

  1. 设置工作目录为/app,这将是容器内部的工作目录。
  2. 使用COPY指令将本地的Go源代码复制到容器中。确保Dockerfile位于Go项目根目录下,以便将整个项目复制到容器。
  3. 使用RUN指令运行go build命令来构建Go应用程序。这将生成一个名为myapp的可执行文件。
  4. 使用EXPOSE指令暴露容器内的端口8080,以便外部可以访问该端口。
  5. 使用CMD指令定义容器启动时要执行的命令,这里是运行myapp可执行文件。

可以将上述Dockerfile保存为文件,然后使用docker build命令来构建容器镜像,假设Go项目位于当前目录下:

docker build -t my-golang-app:1.0 .

接下来,可以使用docker run命令来创建和运行基于该镜像的容器:

docker run -p 8080:8080 my-golang-app:1.0

将创建一个运行Go服务的容器,并将容器内部的端口8080映射到主机上的端口8080,以便通过主机访问该服务。请确保 Go应用程序监听端口8080,以使其正常工作。

3.6 Docker Compose

参考1:Docker Compose和Docker Swarm简析与区别
Compose:是用于定义和运行多容器Docker应用程序的工具【即容器编排】。通过Compose,可以使用YML文件来配置应用程序需要的所有服务,包括容器、网络、卷等。然后,使用一个命令,就可以根据YML文件启动和管理整个应用程序堆栈。

Compose 使用的三个步骤:

  • 使用Dockerfile定义应用程序的环境。
  • 使用docker-compose.yml定义构成应用程序的服务,这样它们可以在隔离环境中一起运行。
  • 最后,执行docker-compose up命令来启动并运行整个应用程序。
  • 执行docker-compose down命令停止程序。

以下是使用docker-compose的基本概念和用法:

  1. Docker Compose文件Docker Compose使用一个名为docker-compose.yml(或docker-compose.yaml)的文件来定义应用程序的配置。这个文件包含了应用程序中各个服务的描述,以及它们之间的关系和依赖。
  2. 服务(Services):一个服务通常对应一个容器,它定义了应用程序的一个组件,例如一个 Web 服务器、数据库、消息队列等。在docker-compose.yml文件中,可以指定服务的镜像、端口映射、环境变量、卷挂载等配置。
  3. 堆栈(Stacks):使用docker-compose启动一组服务时,这组服务被称为一个堆栈。堆栈是一种逻辑上的组织方式,允许将相关的服务一起管理。
  4. 启动应用程序:使用docker-compose up命令可以启动整个应用程序堆栈。Docker Compose会读取docker-compose.yml文件,并按照文件中的配置启动服务。可以通过添加-d标志来以守护进程模式运行应用程序。
  5. 关闭应用程序:使用docker-compose down命令可以停止和删除整个应用程序堆栈的容器、网络和卷。这会清理堆栈中的资源。
  6. 构建镜像:如果需要,可以使用docker-compose build命令来构建自定义的镜像,然后在docker-compose.yml文件中引用这些镜像。
  7. 扩展和伸缩:使用docker-compose,可以轻松扩展应用程序的服务数量,以满足不同的负载需求。例如,可以使用docker-compose scale命令伸缩特定服务的容器数量。
  8. 环境变量和秘密:在docker-compose.yml文件中,可以定义环境变量或引用Docker Swarm的秘密来配置服务,以便在容器中访问敏感信息。
  9. 覆盖文件:可以使用覆盖文件来在不修改原始docker-compose.yml文件的情况下,更改服务的配置或添加额外的配置。这对于不同环境(例如开发、测试和生产)中的不同配置非常有用。

Docker Compose是一个强大的工具,特别适用于开发人员和运维团队,用于本地开发、测试和快速部署多容器应用程序。它简化了多容器应用程序的管理,同时提供了一种一致性的部署方式,以确保应用程序在不同环境中的行为一致。

3.6.1 Docker Compose常用命令

3.6.2 Docker Compose构建golang服务和MySQL数据库的示例

要使用Docker Compose构建一个包含Go服务和MySQL数据库的多容器应用,可以按照以下步骤进行操作:

  1. 创建一个新的目录,用于存放的Go项目文件、Docker Compose配置文件和MySQL初始化脚本。
  2. 在该目录中创建一个Go Web服务的源代码文件,例如main.go,以及一个Dockerfile来构建Go服务的Docker镜像。以下是一个示例Go Web服务的main.go文件,它将连接到MySQL数据库:
package main

import (
	"database/sql"
	"fmt"
	"log"
	"net/http"

	_ "github.com/go-sql-driver/mysql"
)

func handler(w http.ResponseWriter, r *http.Request) {
	// 连接到 MySQL 数据库
	db, err := sql.Open("mysql", "root:password@tcp(database:3306)/mydb")
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	// 执行查询
	rows, err := db.Query("SELECT message FROM messages")
	if err != nil {
		log.Fatal(err)
	}
	defer rows.Close()

	// 处理查询结果
	var message string
	for rows.Next() {
		if err := rows.Scan(&message); err != nil {
			log.Fatal(err)
		}
		fmt.Fprintf(w, "Message from MySQL: %s\n", message)
	}
}

func main() {
	http.HandleFunc("/", handler)
	http.ListenAndServe(":8080", nil)
}
  1. 创建一个Dockerfile文件,用于构建Go服务的Docker镜像。以下是一个示例Dockerfile文件:
# 使用官方的 Golang 镜像作为基础镜像
FROM golang:1.17

# 设置容器内的工作目录
WORKDIR /app

# 复制 Go 源代码到容器中
COPY . .

# 构建 Go 服务
RUN go build -o myapp

# 暴露容器内的端口,此示例服务使用 8080 端口
EXPOSE 8080

# 定义容器启动时执行的命令
CMD ["./myapp"]
  1. 创建一个docker-compose.yml配置文件,定义Go服务和MySQL服务。以下是一个示例docker-compose.yml文件:
version: '3'
services:
  webapp:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "8080:8080"
    depends_on:
      - database
  database:
    image: mysql:8
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: mydb

在这个示例中,我们定义了两个服务:webappdatabase

  • webapp:服务使用构建上下文 (context) 为当前目录,指定了Dockerfile来构建Go服务的镜像。它还将容器内部的端口8080映射到主机上的端口8080,以便通过浏览器访问Web应用。depends_on选项确保webapp服务在database服务之后启动,以便数据库服务准备好后才启动Web服务。
  • database:服务使用官方的MySQL镜像,并设置了环境变量来配置MySQL数据库的根密码和数据库名称。
  1. 在同一目录中创建一个MySQL初始化脚本,用于在容器启动时初始化数据库。创建一个名为init.sql的文件,内容如下:
CREATE TABLE messages (
  id INT AUTO_INCREMENT PRIMARY KEY,
  message VARCHAR(255) NOT NULL
);

INSERT INTO messages (message) VALUES ('Hello, Docker Compose and MySQL!');
  1. 打开终端,导航到包含以上文件的目录,然后运行以下命令,使用Docker Compose启动多容器应用:
docker-compose up

Docker Compose将会根据配置文件创建并启动两个容器,分别运行Go Web服务和MySQL数据库。Go Web服务将连接到MySQL数据库并查询数据。
7. 在浏览器中访问:http://localhost:8080,应该能够看到来自MySQL数据库的消息。
8. 若要停止并删除容器,可以在终端中按下Ctrl+C停止正在运行的Docker Compose进程,然后运行以下命令:

docker-compose down

这个示例演示了如何使用Docker Compose构建和管理一个包含Go服务和MySQL数据库的多容器应用程序。根据项目需求,可以进一步扩展和自定义docker-compose.yml文件以满足需要。

3.7 Docker Swarm

Docker SwarmDocker的集群和编排工具,用于管理和编排多个Docker容器在多个主机上的部署。它允许创建一个Docker集群,将多个Docker主机组合在一起,以便更轻松地管理和扩展容器化应用程序。Docker Swarm提供了以下关键功能:

  1. 容器编排Docker Swarm允许定义容器化应用程序的服务和任务,并确保它们在整个集群中运行,从而轻松进行横向扩展和负载均衡。
  2. 高可用性Docker Swarm提供高可用性特性,可以在集群中保证服务的可用性。它会自动重新调度容器任务到其他可用节点上,以应对容器或节点的故障。
  3. 服务发现Swarm提供内置的服务发现功能,允许容器在集群中相互通信,而无需手动配置网络设置。
  4. 负载均衡Swarm集成了内置的负载均衡功能,可自动将请求分配给运行相同服务的不同容器实例,从而提供更好的性能和容错性。
  5. 安全性Swarm提供了安全性特性,包括节点身份验证、访问控制列表 (ACL) 和加密,以保护容器化应用程序和集群中的数据。
  6. 内置日志和监控Docker Swarm集成了日志记录和监控工具,能够轻松地监视和诊断容器化应用程序。

使用Docker Swarm,可以轻松地创建和管理一个容器编排集群,部署容器化应用程序,并实现高可用性和自动扩展。Swarm的配置文件通常称为docker-compose.yml,与Docker Compose兼容,因此可以无缝地将应用程序从本地开发环境迁移到Swarm集群中。

3.7.1 Docker Swarm常用命令

  1. 初始化一个Docker Swarm集群:
docker swarm init
  1. 将其他Docker主机加入Swarm集群:
docker swarm join --token <token> <manager-ip>:2377
  1. 部署一个服务(例如,Nginx):
docker service create --name my-nginx -p 80:80 nginx
  1. 列出当前Swarm集群的服务:
docker service ls
  1. 扩展服务的副本数:
docker service scale my-nginx=5
  1. 删除一个服务:
docker service rm my-nginx

Docker Swarm是一个强大的容器编排工具,适用于搭建生产环境中的容器化应用程序,使应用程序更易于管理、部署和扩展。它提供了一种容器编排解决方案,使得容器集群的管理变得更加简单和可靠。

3.7.2 Docker Swarm构建golang服务和MySQL数据库的示例

下面是一个示例,演示如何使用Docker Swarm构建一个包含Go服务和MySQL数据库的分布式应用程序。在这个示例中,我们将创建一个Docker Swarm集群,并在该集群上部署一个简单的Go Web服务和一个MySQL数据库。

  1. 创建一个Docker Swarm集群
    首先,初始化一个Docker Swarm集群,可以选择一个节点作为Swarm管理节点(manager),其他节点将加入到这个集群中。
    在管理节点上运行以下命令:
docker swarm init

这将返回一个命令,可以在其他节点上运行以加入集群。例如:

docker swarm join --token <token> <manager-ip>:2377

在其他节点上运行上述命令以加入Swarm集群。

  1. 创建一个docker-compose.yml文件
    在任何一个节点上创建一个名为docker-compose.yml的文件,用于定义服务。以下是一个示例docker-compose.yml文件:
version: '3.8'

services:
  webapp:
    image: my-golang-app:1.0
    ports:
      - "8080:8080"
    deploy:
      replicas: 3
    networks:
      - mynetwork
    depends_on:
      - database
    environment:
      - DATABASE_URL=mysql://myuser:mypassword@database:3306/mydb

  database:
    image: mysql:8
    environment:
      MYSQL_ROOT_PASSWORD: mypassword
      MYSQL_DATABASE: mydb
    networks:
      - mynetwork

networks:
  mynetwork:

此配置文件定义了两个服务:webappdatabasewebapp服务是一个简单的Go Web服务,它运行在端口8080上,并依赖于database服务。database服务是一个MySQL数据库。

  1. 构建和推送Go服务镜像
    在包含Go服务代码的节点上,使用以下命令构建和推送Go服务镜像到Docker镜像仓库(如果有的话):
docker build -t my-golang-app:1.0 .
  1. 部署服务到Swarm集群
    在包含docker-compose.yml文件的节点上,运行以下命令来部署服务:
docker stack deploy -c docker-compose.yml myapp

这将创建一个名为myapp的服务堆栈,并在Swarm集群中部署webappdatabase服务。

  1. 查看服务状态
    可以使用以下命令查看服务状态:
docker stack ps myapp

这将显示服务的运行状态,包括哪个节点上运行每个服务的副本。

  1. 测试应用程序
    使用浏览器或其他工具访问Swarm集群上的任何节点的http://:8080,应该能够访问Go Web服务。该服务将连接到MySQL数据库,执行查询并返回结果。

  2. 扩展和管理服务
    可以使用Docker Swarm的命令来扩展服务、更新服务、管理节点等。例如,要扩展webapp服务的副本数,可以运行:

docker service scale myapp_webapp=5

这会将webapp服务的副本数扩展到5个。

3.8 Docker Stack

Docker Stack是一个用于在Docker Swarm集群中部署分布式应用程序的命令行工具。它建立在Docker Compose文件的基础上,允许定义和部署多个服务,这些服务可以在多个Swarm节点上运行,以实现高可用性和容器编排。

以下是Docker Stack的主要特点和用途:

  1. 应用部署Docker Stack允许使用一个docker-compose.yml文件来定义整个应用程序的多个服务、网络、卷和配置。这个文件可以包含应用程序的所有组件和设置。
  2. 多容器编排:通过Docker Stack,可以轻松地在Docker Swarm集群中部署和编排多个容器。它提供了服务发现、负载均衡、容器间通信等功能。
  3. 高可用性Docker Stack支持高可用性配置,可以确保服务在整个Swarm集群中保持可用。如果某个节点失败,Swarm会自动重新调度任务到其他可用节点上。
  4. 自动负载均衡Docker Stack集成了内置的负载均衡功能,可以自动将请求分发给运行相同服务的不同容器实例,从而提供更好的性能和容错性。
  5. 服务扩展:使用Docker Stack,可以轻松地扩展服务的副本数量,以满足流量和性能需求。这可以通过命令行或更新docker-compose.yml文件来实现。
  6. 栈管理:可以使用Docker Stack来创建、列出、更新和删除服务堆栈。这使得应用程序的生命周期管理更加容易。
  7. 多环境支持Docker Stack支持不同的环境(例如开发、测试和生产),并可以使用不同的docker-compose.yml文件进行部署。

3.8.1 Docker Stack常用命令

  1. 创建一个服务堆栈
docker stack deploy -c docker-compose.yml myapp
  1. 列出正在运行的服务堆栈
docker stack ls
  1. 查看服务堆栈的详细信息
docker stack ps myapp
  1. 扩展服务的副本数量
docker service scale myapp_web=5
  1. 删除服务堆栈
docker stack rm myapp

Docker Stack是一个有力的工具,用于管理Docker Swarm集群中的容器化应用程序。它允许开发人员和运维团队轻松地定义、部署和管理复杂的分布式应用程序,并确保它们在多个节点上运行,并具备高可用性和容器编排的功能。这使得容器化应用程序在生产环境中更容易管理和维护。

3.8.2 Docker Stack构建golang服务和MySQL数据库的示例

以下是一个示例Docker Stack配置,演示如何使用Docker StackDocker Swarm集群中构建一个包含Go服务和MySQL数据库的分布式应用程序。在这个示例中,我们将使用一个简单的Go Web服务连接到MySQL数据库。

  1. 创建一个Docker Swarm集群
    在初始化之前,确保已经创建了一个Docker Swarm集群。可以在其中一个节点上运行以下命令来初始化集群:
docker swarm init

然后,使用输出中提供的docker swarm join命令将其他节点加入到Swarm集群中。

  1. 创建一个目录并进入
    创建一个新的目录,用于存放应用程序代码和Docker Stack配置文件,并进入该目录。
mkdir my-golang-app
cd my-golang-app
  1. 创建一个Go Web服务的源代码文件
    在目录中创建一个名为main.goGo服务源代码文件。以下是一个示例main.go文件,它将连接到MySQL数据库并显示数据库中的消息:
package main

import (
    "database/sql"
    "fmt"
    "log"
    "net/http"

    _ "github.com/go-sql-driver/mysql"
)

func handler(w http.ResponseWriter, r *http.Request) {
    db, err := sql.Open("mysql", "myuser:mypassword@tcp(database:3306)/mydb")
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()

    rows, err := db.Query("SELECT message FROM messages")
    if err != nil {
        log.Fatal(err)
    }
    defer rows.Close()

    var message string
    for rows.Next() {
        if err := rows.Scan(&message); err != nil {
            log.Fatal(err)
        }
        fmt.Fprintf(w, "Message from MySQL: %s\n", message)
    }
}

func main() {
    http.HandleFunc("/", handler)
    http.ListenAndServe(":8080", nil)
}
  1. 创建一个Dockerfile文件
    在同一目录中创建一个名为Dockerfile的文件,用于构建Go服务的Docker镜像。以下是一个示例Dockerfile文件:
# 使用官方的 Golang 镜像作为基础镜像
FROM golang:1.17

# 设置容器内的工作目录
WORKDIR /app

# 复制 Go 源代码到容器中
COPY . .

# 构建 Go 服务
RUN go build -o myapp

# 暴露容器内的端口,此示例服务使用 8080 端口
EXPOSE 8080

# 定义容器启动时执行的命令
CMD ["./myapp"]
  1. 创建一个docker-compose.yml文件
    在同一目录中创建一个名为docker-compose.ymlDocker Stack配置文件。以下是一个示例docker-compose.yml文件:
version: '3.8'

services:
  webapp:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "8080:8080"
    deploy:
      replicas: 3
    networks:
      - mynetwork
    depends_on:
      - database
    environment:
      - DATABASE_URL=mysql://myuser:mypassword@database:3306/mydb

  database:
    image: mysql:8
    environment:
      MYSQL_ROOT_PASSWORD: mypassword
      MYSQL_DATABASE: mydb
    networks:
      - mynetwork

networks:
  mynetwork:

这个配置文件定义了两个服务:webappdatabase,与之前的示例相似。

  1. 构建Go服务的镜像
    在包含Go服务代码的目录中,运行以下命令构建Go服务的Docker镜像:
docker build -t my-golang-app:1.0 .
  1. 使用Docker Stack部署服务
    在包含docker-compose.yml文件的目录中,使用以下命令来部署服务到Swarm集群:
docker stack deploy -c docker-compose.yml myapp
  1. 查看服务状态
    可以使用以下命令查看服务状态:
docker stack ps myapp
  1. 测试应用程序
    使用浏览器或其他工具访问Swarm集群中的任何节点的http://:8080,应该能够访问Go Web服务。该服务将连接到MySQL数据库并执行查询并返回结果。
  2. 扩展和管理服务
    可以使用Docker Stack的命令来扩展服务、更新服务、管理节点等。例如,要扩展webapp服务的副本数,可以运行:
docker service scale myapp_webapp=5

这个示例演示了如何使用Docker Stack构建和管理一个包含Go服务和MySQL数据库的分布式应用程序。根据需求,可以进一步扩展和定制服务以满足复杂应用程序的需求。

3.9 Dockfile 、Compose、Swarm、Stack区别

  1. Dockerfile
    • 用途Dockerfile用于定义和创建容器镜像。它是一个文本文件,包含一系列指令,指导Docker引擎如何构建镜像。
    • 功能Dockerfile包括镜像的基础配置、构建步骤、环境变量、依赖项安装等信息。
    • 示例Dockerfile通常用于构建单个容器镜像,例如一个包含Web服务器的容器镜像。
  2. Docker Compose
    • 用途Docker Compose用于定义和管理多个Docker容器的编排和配置。它通过一个声明性的配置文件来定义应用程序的多个服务、网络、卷以及它们之间的关系。
    • 功能Docker Compose简化了多容器应用程序的部署和管理,可以定义多个容器的组合和交互,并一键启动整个应用程序栈。
    • 示例Docker Compose适用于部署多容器应用程序,如微服务架构,以及将应用程序的不同部分分为多个容器。
  3. Docker Swarm
    • 用途Docker Swarm用于创建和管理Docker容器的集群。它提供容器编排、高可用性、负载均衡和服务发现等功能,使多个 Docker 主机协同工作。
    • 功能Docker Swarm允许容器在多个节点上运行,并提供服务发现、负载均衡、自动恢复和高可用性功能。
    • 示例Docker Swarm适用于部署容器化应用程序到生产环境,以实现容器编排和高可用性。
  4. Docker Stack
    • 用途Docker StackDocker Swarm集群中部署分布式应用程序的命令行工具。它建立在Docker Compose文件的基础上,用于定义和部署多个服务,这些服务可以在多个Swarm节点上运行。
    • 功能Docker Stack可以使用Docker Compose配置文件来部署多容器应用程序,并提供高可用性、负载均衡和容器编排功能。
    • 示例Docker Stack适用于在Docker Swarm集群中部署和管理多容器应用程序,支持多节点部署和容器编排。

总结:
Docker Dockfile用于构建容器镜像,Docker Compose用于编排多容器应用程序的开发环境,Docker Swarm用于管理Docker集群和部署容器化应用程序,而Docker StackDocker Swarm中的一个工具,用于在集群中部署分布式应用程序。这些工具共同构成了Docker生态系统中的不同层次的解决方案,用于容器化应用程序的开发、测试和部署。

3.10 Docker的隔离机制

Docker通过多种隔离机制来确保容器之间和容器与主机之间的资源隔离。这些隔离机制有助于保护应用程序的安全性、稳定性和性能。以下是Docker的主要隔离机制:

  1. 命名空间(Namespaces)Docker使用Linux命名空间来隔离容器的视图,以便它们能够在一个单独的用户空间内运行,而不会干扰其他容器或主机系统。以下是一些常见的命名空间类型:
    • PID命名空间:用于隔离进程ID(PID),每个容器都有自己独立的进程空间。
    • 网络命名空间:用于隔离网络接口和IP地址,每个容器都有自己的网络命名空间。
    • 挂载命名空间:用于隔离文件系统挂载点,每个容器都有自己的文件系统视图。
    • UTS命名空间:用于隔离主机名和域名信息。
    • IPC命名空间:用于隔离进程间通信资源,如共享内存、信号量等。
  2. 控制组(cgroups)Docker使用cgroups来限制和管理容器的资源使用,包括CPU、内存、磁盘I/O等。每个容器可以被分配一定的资源配额,以确保它不会过度消耗主机资源。
  3. 联合文件系统(Union File System)Docker镜像使用分层联合文件系统,允许多个镜像层以只读方式堆叠在一起。这允许容器共享相同的基础层,从而减少存储空间的占用和提高效率。
  4. 容器文件系统: 每个容器都有一个可写层,用于容器运行时的修改。这个层是容器唯一可以写入的部分,其他层都是只读的,以确保文件系统的隔离。
  5. 用户和组Docker容器通常在一个单独的用户空间内运行,每个容器可以有自己的用户和组。这有助于隔离容器内的进程和文件访问权限。
  6. Seccomp(安全计算)Docker支持Seccomp来限制容器中的系统调用。通过Seccomp配置,可以减少容器对主机内核的敏感系统调用,从而提高安全性。
  7. AppArmor和SELinuxDocker可以与Linux的强制访问控制(MAC)机制,如AppArmorSELinux集成,以进一步加强容器的隔离。这些工具可以限制容器对主机资源和文件的访问。
  8. 容器网络隔离Docker提供不同类型的网络隔离,包括桥接网络、主机网络、覆盖网络等,以确保容器之间的通信隔离。这些网络隔离方式使用不同的网络命名空间。

这些隔离机制共同工作,确保容器可以在相对独立和安全的环境中运行,而不会干扰其他容器或主机系统。这使得Docker成为一个强大的容器化平台,适用于各种应用程序和工作负载的隔离需求。但需要注意,虽然Docker提供了许多隔离机制,但仍然需要谨慎配置和管理容器以确保安全性。

3.11 Docker的网络模式

Docker提供了多种网络模式,允许容器之间进行通信以及容器与外部网络连接。选择适当的网络模式取决于应用程序需求和安全性要求。以下是Docker的一些常见网络模式:

  1. 桥接网络(Bridge Network):这是Docker的默认网络模式。在这种模式下,每个容器连接到一个本地虚拟网络桥接,容器可以相互通信,同时也可以通过主机的网络连接到外部网络。这种模式适用于多个容器需要在同一主机上互相通信的情况。
  2. 主机网络(Host Network):在这种模式下,容器与主机共享网络命名空间,容器可以直接使用主机的网络接口。这使得容器与主机之间的网络性能非常高,但也会导致容器与主机之间的网络隔离降低。这种模式适用于需要最大化网络性能的情况。
  3. 覆盖网络(Overlay Network):覆盖网络允许不同Docker主机上的容器相互通信。这对于分布式应用程序和容器编排平台(如Docker SwarmKubernetes)非常有用,因为它允许容器跨主机进行通信。覆盖网络使用VXLAN等技术在不同主机之间建立虚拟网络。
  4. MACVLAN网络(MACVLAN Network):这种模式允许容器分配具有唯一MAC地址的虚拟网络接口。每个容器在网络上看起来像是物理主机的一部分,这对于需要容器与外部网络直接交互的应用程序非常有用。
  5. 无桥接网络(None Network):在这种模式下,容器不会连接到任何网络,这意味着容器无法直接与外部网络通信。这种模式通常用于特定安全需求或测试目的。
  6. 自定义网络(Custom Networks): 可以创建自定义网络,根据应用程序的需要配置网络模式、子网、网关等属性。这种方式允许更精细地控制容器之间的通信和网络配置。

选择适当的网络模式取决于应用程序需求和安全性要求。通常情况下,使用桥接网络是最常见的,因为它提供了良好的隔离性和通信能力,但在某些情况下,可能需要使用其他网络模式来满足特定的需求。 Docker的网络模式灵活,可以根据不同的应用场景进行配置和调整。

3.12 Docker命令

3.12.1 Docker常用命令

  1. 容器生命周期管理
    • docker run :运行一个新的容器。
    • docker start :启动已停止的容器。
    • docker stop :停止运行中的容器。
    • docker restart :重启容器。
    • docker pause :暂停容器的进程。
    • docker unpause :恢复暂停的容器。
    • docker kill :强制停止容器。
    • docker rm :删除一个或多个容器。
    • docker ps:列出运行中的容器。
    • docker ps -a:列出所有容器,包括已停止的。
    • docker logs :查看容器的日志。
    • docker exec -it :在运行的容器中执行命令。
  2. 镜像管理
    • docker pull :拉取镜像。
    • docker push :推送镜像到仓库。
    • docker build :构建自定义镜像。
    • docker images:列出本地镜像。
    • docker rmi :删除本地镜像。
  3. 容器网络管理
    • docker network ls:列出所有网络。
    • docker network inspect :查看网络的详细信息。
    • docker network create :创建自定义网络。
    • docker network connect :将容器连接到网络。
    • docker network disconnect :将容器从网络断开。
  4. 容器数据管理
    • docker volume ls:列出所有卷。
    • docker volume create :创建卷。
    • docker volume inspect :查看卷的详细信息。
    • docker volume rm :删除卷。
    • docker cp : :从容器复制文件到主机。
    • docker cp ::从主机复制文件到容器。
  5. 其他常用命令
    • docker info:查看Docker系统信息。
    • docker version:查看Docker版本信息。
    • docker login:登录到Docker Hub或其他Docker仓库。
    • docker logout:退出登录。
    • docker search :搜索Docker Hub上的镜像。
    • docker-compose :使用Docker Compose管理多容器应用程序。

3.12.2 Docker挂载文件的命令

Docker允许将主机文件系统上的文件或目录挂载到容器内部,以便容器可以访问这些文件。这是通过-v--volume选项来实现的。以下是挂载文件的Docker命令示例:

  1. 将主机文件挂载到容器内部
docker run -v /host/path:/container/path <image>
  • /host/path:是主机上的文件或目录路径。
  • /container/path:是容器内部的挂载点路径。
  • :是要运行的Docker镜像。
    例如,要将主机上的/app/data目录挂载到容器内的/data目录,可以运行以下命令:
docker run -v /app/data:/data myapp_image
  1. 将主机当前目录挂载到容器内部
docker run -v $(pwd):/container/path <image>

这个命令将主机的当前工作目录挂载到容器内的指定路径。

  1. 挂载具有读写权限的卷
docker run -v /host/path:/container/path:rw <image>

通过添加:rw选项,可以将卷以读写模式挂载到容器内。

  1. 挂载匿名卷
docker run -v /container/path <image>

如果省略主机路径,则Docker将创建一个匿名卷,并将其挂载到容器内的指定路径。匿名卷可以用于临时数据存储。

请注意,挂载文件或目录可以在容器和主机之间进行双向数据传输,因此容器对这些文件的更改将反映在主机上,反之亦然。挂载是非常有用的,因为它允许容器访问主机上的配置文件、数据或其他资源,同时也提供了一种简单的方式来在主机和容器之间共享数据。

3.12.3 Docker中查看Pod日志的命令

Docker中,容器是最小的可部署单元,而Pod通常是Kubernetes中用于组织容器的概念。如果要查看容器的日志,可以使用Docker命令,但如果正在使用Kubernetes或其他容器编排工具来管理容器,通常需要使用相应的工具来查看Pod日志。

Docker中查看容器日志的命令:

  1. 使用docker logs命令查看容器日志
docker logs <container_id>

其中是要查看日志的容器的ID或名称。这将显示容器的标准输出和标准错误日志。如果容器已经停止,仍然可以使用这个命令来查看容器的最后一次运行时的日志。

  1. 使用docker logs命令实时查看容器日志
docker logs -f <container_id>

添加-f标志,可以实时跟踪容器的日志输出,这对于查看容器当前正在发生的事情非常有用。

请注意,这些命令用于查看单个容器的日志。如果正在使用Kubernetes或其他容器编排工具,通常需要使用该工具提供的命令来查看Pod日志,因为Pod可以包含多个容器。

Kubernetes中,可以使用以下命令来查看Pod的日志:

  1. 使用kubectl logs命令查看Pod日志
kubectl logs <pod_name> -c <container_name>
  • :是Pod的名称。
  • :是要查看日志的容器的名称。如果Pod中只有一个容器,可以省略-c选项。
  1. 实时查看Pod日志
kubectl logs -f <pod_name> -c <container_name>

添加-f标志,可以实时跟踪日志输出。

这些命令适用于Kubernetes中的Pod,用于查看每个容器的日志。如果使用的是其他容器编排工具,具体的命令可能会有所不同,但一般原理是类似的:首先选择Pod,然后选择容器,最后使用相关命令查看日志。

3.12.4 Docker崩溃后自动重启的命令

假设你有一个docker镜像叫做coolimage:v1,如何运行该镜像?需要保证即使容器内部的程序崩溃了,该容器依然能自动恢复;同时需要保证当主机重启之后,该容器能够自动运行起来。

答:①运行镜像的命令:docker run coolimage --restart always


Docker本身不提供自动重启容器的功能。然而,可以使用一些外部工具和策略来实现在Docker容器崩溃或停止后自动重启容器的目标。以下是一些方法:

  1. 使用Docker Compose: 如果使用Docker Compose来管理容器,可以在docker-compose.yml文件中为每个服务定义重启策略。例如,可以将restart字段设置为"always",以指定容器应该始终自动重启:
services:
  my-service:
    image: my-image
    restart: always
  1. 使用Docker Swarm: 如果使用Docker Swarm来编排容器,可以使用--restart标志来设置容器的重启策略。例如,以下命令将创建一个服务并设置它在崩溃或停止时自动重启:
docker service create --name my-service --restart-condition any my-image
  1. 使用容器编排工具: 如果使用Kubernetes或其他容器编排工具,这些工具通常提供了管理容器重启策略的功能,可以在PodDeployment配置中定义重启策略。
  2. 使用监控和自动恢复工具: 还可以考虑使用监控和自动恢复工具,如DockerHealthcheckSupervisorSystemd等。这些工具可以监测容器的健康状态,当容器崩溃时触发自动重启。
  3. 使用第三方工具: 有一些第三方工具,如Docker自动重启脚本或监控工具,可以监测Docker容器并在容器崩溃时自动重启。这些工具可以根据需求进行定制。

注意:
自动重启容器可能会在某些情况下隐藏问题,因此在实施自动重启策略之前,建议仔细考虑容器的稳定性和问题排查。确保了解为什么容器会崩溃,并采取适当的措施来解决根本问题,以确保应用程序的稳定性。

3.12.5 Docker打包镜像的操作【golang项目】

参考1:https://www.jianshu.com/p/f1c34772f058

完整的Dockerfile:

# 编译镜像
FROM golang:1.16-alpine AS build

WORKDIR /project/
COPY ./project /project
RUN go env -w GOPROXY=https://goproxy.io,direct
RUN go build -o /project/work/server main.go

# 运行镜像
FROM alpine
ENV TZ Asia/Shanghai
COPY --from=build /project/work/ /work/

# 定义工作目录为work
WORKDIR /work
# 开放http 80端口
EXPOSE 80
# 启动http服务
ENTRYPOINT ["./server"]

构建并推送镜像:

# 在Dockerfile所在文件夹运行
docker build -t xxxx/xxxx:v1 .

# 构建成功后,运行测试一下
docker run -d xxxx/xxxx:v1

# docker ps查看一下运行情况
docker ps

# 查看一下容器对应的pid
docker inspect 554c4578242e|grep -i pid

# 查看对应的IP配置
nsenter -t 256418 -n ip a

3.12.6 Docker构建镜像的命令

Docker中,可以使用docker build命令来构建自定义的镜像。要构建镜像,需要创建一个名为Dockerfile的文件,其中包含有关如何构建镜像的指令。然后,使用以下命令构建镜像:

docker build -t <image_name>:<tag> <path_to_Dockerfile_directory>

以下是各个部分的解释:

  • :要创建的镜像的名称。
  • :要分配给镜像的标签(可选),通常用于版本控制。如果不指定标签,默认为latest
  • :包含Dockerfile的目录的路径。Docker将在该目录中查找Dockerfile并使用它来构建镜像。

以下是一个示例,演示如何构建一个名为myapp的镜像,标签为v1.0Dockerfile位于当前目录下:

docker build -t myapp:v1.0 .

Docker将会读取Dockerfile并执行其中的指令,这些指令包括基础镜像选择、安装软件包、拷贝文件等。在构建过程中,Docker将创建一系列的镜像层,这些层包含了构建过程中的每个步骤,以便后续的重用和版本控制。

一旦构建完成,可以使用以下命令来列出新构建的镜像:

docker images

这会显示创建的镜像以及它们的标签和其他信息。

请确保在构建镜像之前正确编写和测试Dockerfile,以确保镜像包含期望的应用程序和配置。构建的镜像可以用于启动容器,以便在各种环境中运行应用程序。

3.13 Docker Compose部署的服务,如果有一个挂了,它是怎么重新发送到正常服务里的,怎么实现的?

Docker Compose本身并不提供高可用性(High Availability, HA)功能。Docker Compose用于定义和运行多个Docker容器的应用程序堆栈,通常在单个主机上运行。要实现Docker应用的高可用性,通常需要考虑以下几个方面:

  1. 使用编排工具Docker Compose适用于本地开发和测试,它通常不用于生产环境的高可用性。对于生产环境,可以考虑使用编排工具,如Docker SwarmKubernetes或其他容器编排工具,以实现容器应用的高可用性。
  2. 容器编排: 使用容器编排工具,可以将容器部署到多个主机上,并配置容器的副本以确保服务的冗余和高可用性。这些工具还提供故障恢复和自动扩展功能。
  3. 数据存储高可用: 对于需要数据持久性的应用程序,确保数据库和存储解决方案具有高可用性配置。这可能涉及到复制、分区、备份等机制,以确保数据不会因单点故障而丢失。
  4. 负载均衡: 高可用的应用程序通常使用负载均衡器来将流量分发到多个容器实例。这有助于确保即使其中一个容器实例出现问题,流量仍然可以被正确路由到其他正常工作的实例。
  5. 监控和自动恢复: 使用监控工具来检测容器或主机的故障,以及应用程序的性能问题。配置自动恢复机制,以便在故障发生时能够快速恢复服务。
  6. 容器注册中心: 使用容器编排工具通常需要一个容器注册中心,如Consuletcd,以存储和管理容器和服务的状态信息。这有助于实现服务发现、故障恢复和负载均衡。
  7. 存储卷和数据管理: 确保应用程序在容器重启或重新部署时不会丢失重要数据。使用Docker卷或外部存储解决方案,以确保数据的持久性和高可用性。
  8. 多区域部署: 如果应用程序需要更高级别的高可用性,考虑在多个数据中心或云区域中部署,并设置跨区域的负载均衡和故障恢复策略。

总结Docker Compose适用于本地开发和测试,但对于生产环境中的高可用性,需要使用适当的容器编排工具,并采取适当的措施来确保容器应用的冗余、故障恢复和性能。具体的配置和实施取决于应用程序和基础架构需求。

3.14 Docker与虚拟机的区别

Docker和虚拟机(VM)是两种不同的虚拟化技术,它们在多个方面有着明显的区别。以下是Docker和虚拟机之间的主要区别:

  1. 架构差异
    • DockerDocker是一种容器化技术,它利用操作系统的容器化功能来隔离应用程序和其依赖项。每个Docker容器共享主机操作系统的内核,但拥有自己的用户空间。这使得Docker容器轻量且启动迅速。
    • 虚拟机:虚拟机是一种基于Hypervisor的虚拟化技术,它模拟了完整的硬件层,每个虚拟机都运行一个完整的操作系统,包括内核。这导致虚拟机相对较重,并且启动速度较慢。
  2. 资源利用效率
    • Docker:由于Docker容器共享主机操作系统的内核,因此它们更加轻量,需要更少的资源。多个容器可以在同一主机上运行而不会显著增加资源消耗。
    • 虚拟机:虚拟机需要模拟整个操作系统,因此每个虚拟机通常需要较多的资源,包括内存和磁盘空间。这限制了在同一主机上运行的虚拟机数量。
  3. 启动时间
    • DockerDocker容器的启动时间通常非常快,几乎可以瞬间启动。这使得Docker容器非常适合快速扩展和缩减。
    • 虚拟机:虚拟机的启动时间相对较长,通常需要几分钟来启动,因为它们必须启动整个操作系统。
  4. 隔离性和安全性
    • DockerDocker容器提供了良好的进程隔离,但容器共享主机操作系统的内核,因此容器之间有一定的安全风险。 Docker引入了一些安全性功能,如命名空间和Seccomp,以提高容器的安全性。
    • 虚拟机:虚拟机提供更高级别的隔离,每个虚拟机都有独立的内核。这增加了虚拟机之间的隔离程度,使其更适合多租户环境和安全性要求严格的工作负载。
  5. 镜像管理
    • DockerDocker使用分层文件系统和Docker镜像来轻松创建、分享和管理容器。镜像可以非常高效地共享和复用。
    • 虚拟机:虚拟机镜像通常较大,复制和传输的成本更高,镜像管理相对较为复杂。

总结:
Docker更适合轻量级应用程序容器化和快速部署,而虚拟机通常更适合要求更严格的隔离和安全性的工作负载。选择使用哪种虚拟化技术取决于特定需求和应用场景。在某些情况下,Docker和虚拟机可以结合使用,以充分利用它们各自的优势。

3.15 Docker容器有几种状态

  1. 运行中(Running):容器正在正常运行,其内部的应用程序或服务正在执行。
  2. 停止(Exited):容器已经停止,其内部的应用程序或服务已经退出或被停止。这可能是因为容器的主进程已完成或手动停止了容器。
  3. 暂停(Paused):容器的所有进程都被暂停,但容器的状态保持不变。容器可以被恢复以恢复正常运行。
  4. 创建中(Creating):容器正在创建,Docker正在初始化容器的资源和环境。
  5. 终止中(Terminating):容器正在被停止或删除。这个状态表示容器正在进行清理操作。
  6. 重启中(Restarting):如果使用了重启策略(如--restart选项),容器在崩溃或退出后会尝试重新启动。这个状态表示容器正在重新启动。

这些状态反映了容器的当前状态,可以使用docker ps -a命令来查看容器的状态以及其他相关信息。容器状态的管理和监控对于运维容器化应用程序非常重要,以确保容器的稳定性和可用性。

3.16 DockerFile中的命令COPY和ADD命令有什么区别

Dockerfile中,COPYADD命令都用于将文件或目录从主机系统复制到容器内部,但它们有一些重要的区别:

  1. COPY命令
    • COPY命令用于将本地文件或目录复制到容器内部。它的语法如下:
    COPY <src> <dest>
    # 是主机上的源文件或目录的路径。
    # 是容器内部的目标路径。
    
    • COPY命令只复制本地文件系统上的文件或目录到容器,不执行额外的解压缩或处理操作。这使得它更加可预测和透明。
    • COPY命令通常用于将应用程序代码、配置文件等静态文件复制到容器中。
  2. ADD命令
    • ADD命令也用于将本地文件或目录复制到容器内部。它的语法如下:
    ADD <src> <dest>
    # 是主机上的源文件或目录的路径。
    # 是容器内部的目标路径。
    
    • COPY不同,ADD命令具有附加功能,它可以处理网络上的URL、压缩文件(如.tar.zip)以及自动解压缩文件。这使得ADD命令更灵活,但也更复杂。
    • 使用ADD命令时要小心,因为它可能导致意外行为。例如,如果是一个URL,容器构建可能会因为网络问题而失败,或者可能会导致每次构建时都重新下载文件。

总的来说,COPY命令更加简单和可预测,适用于复制本地文件或目录到容器。而ADD命令具有更多的功能,但需要小心使用,以避免意外行为。通常情况下,如果只需要复制文件或目录,建议使用COPY命令,而在需要处理特殊情况时再考虑使用ADD命令。

3.17 如何批量清理临时镜像文件

要批量清理Docker中的临时镜像文件,可以使用Docker提供的docker system prune命令。此命令可用于删除不再使用的镜像、容器、卷和网络资源,以释放磁盘空间。

以下是如何使用docker system prune命令进行批量清理的步骤:

  1. 打开终端,并确保以Docker管理员或拥有足够权限的用户身份登录。
  2. 运行以下命令以清理不再使用的临时镜像文件:docker system prune,这将会列出要删除的临时镜像文件以及将删除的总数量。程序会要求确认操作。
  3. 如果需要自动确认并删除,可以使用-f--force选项:docker system prune -f,这将跳过确认提示,立即删除不再使用的资源。
  4. 如果只想清理特定类型的资源,可以使用子命令,例如清理未被使用的容器、卷、网络或镜像:
    • 清理未被使用的容器:docker container prune
    • 清理未被使用的卷:docker volume prune
    • 清理未被使用的网络:docker network prune
    • 清理未被使用的镜像:docker image prune

请注意,清理操作是不可逆的,一旦删除,无法恢复。因此,在执行清理操作之前,请确保了解要删除的资源,以免意外删除重要数据。

另外,如果需要定期清理Docker资源,可以设置定时任务或脚本来自动运行docker system prune -f或其他适当的清理命令。这有助于保持磁盘空间的干净和可用。

3.18 如何查看镜像支持的环境变量

查看Docker镜像支持的环境变量,可以使用以下步骤:

  1. 运行容器:首先,需要运行该镜像的一个容器实例。可以使用docker run -it /bin/bash命令启动一个容器,并将进入其Shell,请将替换为要查看的镜像的名称或ID。这会启动一个交互式容器。
  2. 查看环境变量:一旦进入容器的Shell,可以使用env命令查看环境变量,这将显示容器内部的所有环境变量及其值。可以滚动查看列表以查找感兴趣的特定环境变量。
  3. 退出容器:当查看完环境变量后,可以使用exit命令退出容器并返回到主机系统的终端。

请注意,这种方法只能查看镜像在运行时设置的环境变量。如果镜像的环境变量是在Dockerfile中设置的,那么可以查看Dockerfile以了解它们的定义。此外,一些应用程序可能会动态加载环境变量,这些变量可能不会在容器启动时立即可见,而是在应用程序运行时设置。

3.19 本地的镜像文件都存放在哪里

本地的Docker镜像文件存储在Docker守护程序的数据目录中。Docker数据目录的位置因操作系统而异:

  1. Linux:在大多数Linux发行版中,Docker数据目录通常位于/var/lib/docker。镜像文件和其他Docker相关数据存储在这个目录中。
  2. Windows:在Windows上,Docker数据目录通常位于C:\ProgramData\Docker。这个目录包含了Docker镜像和容器数据。
  3. macOS:在macOS上,Docker数据目录通常位于/var/lib/docker,与Linux类似。请注意,在macOS上,Docker使用的是HyperKit虚拟化技术。

Docker镜像文件存储在数据目录的子目录中,其中包括镜像的层(layers)、容器的元数据和其他相关数据。具体的存储路径和目录结构可能会因Docker版本和配置而异,但通常情况下,不需要手动操作这些文件,Docker会负责管理它们。

如果想要查看Docker数据目录的位置,可以运行以下命令来查看Docker的配置信息:

docker info

在输出中,查找名为"Data Root"的项,它将显示Docker数据目录的路径。

请注意,如果不是管理员或没有足够的权限,可能无法访问Docker数据目录中的文件。对Docker数据目录进行直接操作通常是不推荐的,而应该使用Docker命令和API来管理容器和镜像。

3.20 容器退出后,通过docker ps命令查看不到,数据会丢失么

当容器退出后,通过docker ps命令查看不到容器的时候,容器的元数据会被清除,但容器内的数据通常不会立即丢失:

  1. 容器元数据Docker容器在运行时会有一个相应的元数据记录,包括容器的名称、ID、状态等信息。当容器退出(例如,正常停止或发生错误导致退出)时,这些元数据记录会被清除,所以通过docker ps命令查看不到已经退出的容器。

  2. 容器数据:容器的数据(文件系统等)通常不会立即删除。Docker会保留容器的数据,以便可以随时重新创建容器并访问先前运行的容器内部的数据。

    如果想要重新启动已经退出的容器,可以使用容器的名称或ID来重新创建它,例如:docker start ,这将重新启动容器,并且可以通过docker ps查看到运行中的容器。

    但是,请注意以下几点:

    • 如果在容器退出之前没有使用docker commit命令将其保存为新的镜像,容器内所做的更改将不会被保留。
    • 如果手动删除了容器(使用docker rm命令),那么容器的数据将被删除,除非在删除容器时使用了-v选项来保留卷数据。
    • 数据的保留时间也受到Docker存储驱动程序的影响,不同的存储驱动程序可能会有不同的行为。

如果希望容器的数据永久保存,通常的做法是将数据卷挂载到容器中,这样即使容器退出,数据卷中的数据仍然会被保留。

3.21 如何停止所有正在运行的容器

要停止所有正在运行的Docker容器,可以使用以下命令:

docker stop $(docker ps -q)

这个命令执行了以下两个步骤:

  1. docker ps -q:这个命令将列出当前正在运行的容器的ID,每个ID占据一行。 -q标志表示仅输出容器的ID,而不包括其他信息。
  2. docker stop:然后,使用docker stop命令来停止列出的所有容器。$(docker ps -q) 将上一步中列出的容器ID作为参数传递给docker stop命令。

请注意,这个命令将会停止所有正在运行的容器,包括正在执行的应用程序。确保在执行此命令之前,已经保存了必要的数据或状态。

如果只想停止特定容器,可以使用docker stop命令,后跟容器的名称或ID。例如:

docker stop my_container

3.22 如何清理批量后台停止容器

要清理并批量删除后台停止的容器,可以使用以下步骤:

  1. 查找并列出后台停止的容器:使用docker ps -q -f "status=exited"命令来列出后台停止的容器,这个命令使用-q标志仅输出容器的ID,并使用-f标志来筛选状态为"exited"(已停止)的容器。
  2. 批量删除容器:使用docker rm命令来批量删除列出的容器。可以将上一步中列出的容器ID作为参数传递给docker rm命令,docker rm $(docker ps -q -f "status=exited"),这将删除所有后台停止的容器。

如果只想删除特定容器,可以将容器的名称或ID传递给docker rm命令。例如:

docker rm my_container

这将删除名为my_container的容器。请谨慎使用docker rm命令,因为删除容器后,与容器关联的数据也将被删除。

请注意,这个操作不会删除镜像,只会删除容器。如果需要删除不再使用的镜像,可以使用docker image prune命令,这将删除未被任何容器引用的镜像,以释放磁盘空间。

3.23 如何临时退出一个正在交互的容器的终端,而不终止它

在一个正在交互的Docker容器终端中,如果想临时退出而不终止容器,可以使用以下方法:

  1. Ctrl+P,Ctrl+Q组合键
    • 在容器终端内,按下Ctrl+P键,然后按下Ctrl+Q键,这将退出容器终端,但容器本身会保持运行状态。
    • 请确保按下Ctrl键不要释放,然后按下PQ键,最后释放Ctrl键。
  2. 使用docker attach重新连接
    • 使用docker ps命令查找容器的ID或名称。
    • 然后使用docker attach命令重新连接到容器的终端,如下所示:
    docker attach <container_id_or_name>
    
    这将重新连接到容器的终端,能够再次与容器交互。

请注意,使用Ctrl+PCtrl+Q组合键退出容器终端后,可以使用docker attach命令或docker exec命令来重新连接到容器的终端进行进一步的交互。这种方式可以保持容器的运行状态,不会终止容器。

3.24 很多应用容器都是默认后台运行的,怎么查看它们的输出和日志信息

  1. 使用docker logs命令
    • 使用docker ps命令列出正在运行的容器,并找到要查看的容器的名称或ID。
    • 使用docker logs命令来查看容器的标准输出和标准错误日志。例如:docker logs ,这将显示容器的输出和日志信息,可以用来查看应用程序的运行情况。
  2. 使用docker attach命令
    • 使用docker ps命令找到容器的名称或ID。
    • 使用docker attach命令来连接到容器的终端,例如:docker attach ,这将连接到容器的终端,允许查看实时输出和日志信息。要从终端断开连接,可以按下Ctrl+C组合键。
  3. 使用容器日志驱动程序
    • Docker支持不同的容器日志驱动程序,如json-file、syslog、journald等。可以在创建容器时通过--log-driver选项来指定使用的日志驱动程序,以及其他相关配置。
    • 使用docker logs命令查看容器的输出和日志信息时,将使用所配置的日志驱动程序。
  4. 使用监控和日志集成工具
    • 对于复杂的应用程序,可以考虑使用监控和日志集成工具,如ELK Stack(Elasticsearch、Logstash、Kibana)Prometheus等,来集中管理和分析容器日志。

通过这些方法,可以查看和管理正在后台运行的容器的输出和日志信息,以便监控和排查问题。根据需求,可以选择适当的方法来查看容器的日志。

3.25 使用docker port命令映射容器的端口时,系统报错Error:NO public port ‘80’ published for …,是什么意思

当使用docker port命令尝试查看容器的端口映射时,如果出现"Error: No public port '80' published for ..."错误,这通常意味着容器在端口80上没有公开(映射)端口。

这个错误的原因可能有以下几种:

  1. 端口未映射:尝试查看的容器没有将其端口映射到主机的任何公开端口。这可能是因为在运行容器时没有使用-p-P选项来映射端口。
  2. 错误的端口号:可能尝试查看一个容器上没有的端口号。请确保使用的是正确的端口号。

要解决这个问题,可以执行以下步骤:

  1. 使用docker ps命令查看容器的详细信息,包括端口映射。查找"PORTS"列,以确定容器上已经映射到主机的端口。
  2. 如果端口确实没有映射,可以在运行容器时使用-p选项来映射端口。例如,要将容器的端口80映射到主机的端口8080,可以运行以命令:docker run -d -p 8080:80
  3. 重新运行容器后,再次使用docker port命令来查看映射的端口。

3.26 可以在一个容器中同时运行多个应用进程吗

可以,不推荐。

Docker容器的最佳实践通常是一个容器只运行一个主要的应用进程。虽然在一个容器中同时运行多个应用进程是技术上可行的,但这并不是推荐的做法,因为它会引入一些挑战和问题:

  1. 进程管理复杂性:在一个容器中同时运行多个应用进程可能需要复杂的进程管理和监控,包括启动、停止、重启、错误处理等。这可能导致容器的复杂性增加,难以管理。
  2. 日志和输出管理:多个应用进程将共享标准输出和标准错误流,这可能导致日志混淆,难以追踪问题和分析日志。
  3. 资源管理:多个应用进程共享容器的资源,如CPU和内存。这可能会导致资源争用和性能问题。
  4. 隔离性:容器是用来隔离应用程序的,多个应用进程在同一个容器中运行可能会减弱隔离性,增加安全风险。
  5. 可维护性:当需要升级或更改其中一个应用程序时,可能需要重新构建整个容器,而不仅仅是更改一个应用进程。这可能会导致不必要的复杂性和资源浪费。

为了更好地利用Docker的优势,通常建议将每个容器设计成一个独立的、单一用途的容器,只运行一个主要的应用进程。如果需要运行多个服务,可以使用Docker ComposeKubernetes等容器编排工具来协调多个容器的运行。

总之,虽然可以在一个容器中运行多个应用进程,但这不是最佳实践,容易引入复杂性和问题。推荐的方式是将每个容器用于一个独立的应用程序,并使用容器编排工具来管理多个容器之间的关系和依赖。

3.27 如何控制容器占用系统资源(CPU,内存)的份额

可以使用Docker提供的一些选项和限制来控制容器占用系统资源(如CPU和内存)的份额。这可以帮助确保容器在共享主机上的资源时不会无限制地占用资源,从而保证系统的稳定性。以下是一些常见的资源控制方法:

  1. CPU份额限制
    • 使用--cpu-shares-c选项来设置容器的CPU份额。这个值表示容器在CPU资源上的相对权重,可以是一个整数值。例如,以下命令将容器的CPU份额设置为512,相对于其他容器的权重:
    docker run -d --cpu-shares 512 my_container
    
    默认情况下,每个容器的CPU份额为1024。如果将容器的CPU份额设置为512,它将获得相对于默认份额的一半CPU时间。
    • 使用--cpus选项来设置容器可以使用的CPU核心数量。例如,以下命令将容器限制为使用一个CPU核心:
    docker run -d --cpus 1 my_container
    
  2. 内存限制
    • 使用--memory选项来设置容器的内存限制。可以指定限制的值,并可以使用单位(例如MBGB)来表示。例如,以下命令将容器的内存限制设置为512MB
    docker run -d --memory 512m my_container
    
    • 使用--memory-swap选项来设置容器的总内存限制,包括物理内存和交换空间。默认情况下,它是无限制的。例如,以下命令将容器的内存限制设置为512MB,交换空间为1GB
    docker run -d --memory 512m --memory-swap 1g my_container
    

3.28 从非官方仓库(如:dl.dockerpool.com)下载镜像的时候,有时候会提示"Error:Invaild registry endpointhttps://dl.docker.com:5000/v1/…"

如果尝试从非官方仓库(如dl.dockerpool.com)下载镜像时出"Error: Invalid registry endpoint https://dl.docker.com:5000/v1/..."错误,这可能是因为Docker配置中的镜像仓库配置不正确或有误。

以下是一些可能的原因和解决方法:

  1. 仓库地址错误:提供的镜像仓库地址(registry endpoint)可能不正确。请确保使用正确的镜像仓库地址。在docker pull命令中,或者在Docker Compose文件或Dockerfile中,检查是否有任何错误的仓库地址。
  2. 仓库地址包含端口号:如果指定了端口号,确保它与仓库实际使用的端口号匹配。默认的Docker仓库端口号是80,但有些仓库可能使用其他端口号。
  3. HTTP和HTTPS:仓库地址可能使用了HTTPS,但是Docker配置没有正确配置HTTPS代理或证书。如果是这种情况,请确保Docker配置正确并具有所需的证书。
  4. Docker仓库的可访问性:请确保可以访问指定的Docker仓库。有时候网络问题或防火墙设置可能会阻止访问特定仓库。
  5. Docker仓库的状态:有时,非官方仓库可能会不稳定或离线。在这种情况下,可能需要等待一段时间或考虑使用其他镜像仓库。

如果确定镜像仓库地址是正确的,并且仍然遇到问题,可以尝试运行以下命令来清除Docker缓存并重试:

docker system prune -a
docker pull <image_name>

这将清除Docker的镜像缓存并重新尝试下载镜像。如果问题仍然存在,请检查Docker配置和网络设置,确保没有任何问题阻止了与镜像仓库的通信。

3.29 Docker的配置文件放在那里?如何修改配置

Docker的配置文件通常位于操作系统中的不同位置,具体位置取决于操作系统和Docker版本。以下是一些常见的Docker配置文件的位置:

  1. LinuxDocker的主要配置文件通常位于/etc/docker/目录下。其中,/etc/docker/daemon.json文件是Docker守护程序的配置文件,可以在其中指定各种Docker配置选项。
  2. Windows:在Windows上,Docker Desktop for Windows使用JSON文件来配置Docker。配置文件通常位于%USERPROFILE%\.docker\config.json。可以使用文本编辑器打开此文件进行编辑。
  3. macOS:在macOS上,Docker Desktop for Mac使用JSON文件配置,通常位于~/.docker/config.json。可以使用文本编辑器打开此文件进行编辑。

要修改Docker的配置文件,可以按照以下步骤进行操作:

  1. 打开适当位置的配置文件(如上所述),使用喜欢的文本编辑器。
  2. 编辑配置文件以添加、删除或修改相应的配置选项。请注意,Docker配置文件是JSON格式的,因此请确保遵循JSON语法。
  3. 保存配置文件。
  4. 重启Docker守护程序以使配置更改生效。可以使用以下命令来重新启动Docker守护程序:
    • Linux上:sudo systemctl restart docker
    • Windows上:在Docker Desktop应用程序中,可以通过右键单击Docker图标并选择"Restart"来重新启动Docker
    • macOS上:在Docker Desktop for Mac应用程序中,可以通过点击Docker图标并选择"Restart Docker"来重新启动Docker

注意:
不要随意更改Docker配置文件,除非完全了解要进行的更改,因为错误的配置可能会导致Docker守护程序无法启动或应用程序无法正常工作。修改配置文件时,请备份原始文件以便恢复。

3.30 如何更改docker的默认存储设置

要更改Docker的默认存储设置,需要编辑Docker守护程序的配置文件,并指定新的存储驱动程序或存储选项。存储驱动程序是Docker用于管理容器和镜像数据的组件之一,它定义了数据在主机上的存储方式。以下是一些常见的存储设置更改方法:

注意:在进行存储设置更改之前,请确保了解更改可能会对现有容器和镜像产生的影响。

  1. 更改存储驱动程序:默认情况下,Docker使用overlay2存储驱动程序(在大多数现代Linux系统上)。如果希望更改存储驱动程序,请按照以下步骤操作:
    • 打开Docker守护程序的配置文件。在Linux上,通常位于/etc/docker/daemon.json
    • 添加或编辑"storage-driver"配置项,指定新的存储驱动程序名称。例如,要切换到"aufs"存储驱动程序:
    {
      "storage-driver": "aufs"
    }
    
    • 保存配置文件,并重启Docker守护程序以使更改生效。
  2. 更改存储驱动程序选项:还可以更改存储驱动程序的选项,以调整存储设置。例如,可以更改overlay2存储驱动程序的配置。在Docker守护程序配置文件中,可以添加一个"storage-opt"配置项,用于指定存储驱动程序选项。例如:
    {
      "storage-driver": "overlay2",
      "storage-opt": {
        "overlay2.override_kernel_check": "true"
      }
    }
    

这个示例更改了overlay2存储驱动程序的一个选项以允许覆盖内核检查。
3. 更改Docker数据目录:默认情况下,Docker数据目录位于/var/lib/docker。如果需要更改Docker数据目录的位置,可以使用data-root配置项。例如:

{
  "data-root": "/path/to/new/docker/data"
}

请确保新目录具有足够的磁盘空间,并且具有适当的权限。
4. 其他存储相关设置Docker守护程序的配置文件还包含其他与存储相关的选项,例如存储驱动程序的默认选项,存储池大小等。可以根据需要编辑这些选项。
5. 重启Docker守护程序:最后,保存配置文件并重启Docker守护程序,以使更改生效。在Linux上,使用以下命令重启Docker守护程序:sudo systemctl restart docker

注意:
在进行存储设置更改之前,务必备份原始配置文件以防万一。另外,确保仔细阅读Docker文档和存储驱动程序文档,以确保了解所做更改的含义和潜在影响。

3.31 Docker与LXC(Linux Container)有何不同

DockerLXC(Linux Containers)都是容器化技术,用于在Linux操作系统上创建和管理容器。尽管它们有一些共同之处,但它们在一些关键方面有很大的不同:

  1. 抽象级别
    • Docker是一个高级容器管理工具,它提供了一个简化的容器构建、部署和管理的用户友好界面。Docker引入了Docker镜像和Docker Hub等概念,使容器化变得更加容易。
    • LXC是一个更低级别的容器技术,提供了更原始的容器操作接口。LXC容器通常需要更多的手动配置和管理。
  2. 镜像和分发
    • Docker使用Docker镜像作为容器的构建和分发单元。镜像包含应用程序、运行时和所有依赖项,使得容器在不同环境中可移植。
    • LXC容器通常需要手动创建和配置,没有像Docker镜像那样的分发和版本控制机制。
  3. 隔离和安全性
    • Docker强调应用程序隔离和安全性,尽管它使用了Linux内核提供的容器技术(如cgroups和命名空间),但它添加了一层额外的隔离和安全性措施。
    • LXC容器提供了更原生的Linux进程隔离,较少的隔离措施可能需要手动配置。
  4. 生态系统和工具
    • Docker拥有庞大的生态系统,包括Docker ComposeDocker SwarmKubernetes等工具,用于容器编排和管理。Docker Hub也是一个容器镜像仓库,方便共享和分发容器镜像。
    • LXC虽然有一些关联工具,但它的生态系统相对较小,没有与Docker相同的广泛支持和社区。
  5. 用途
    • Docker通常用于构建和运行单个容器化应用程序,适用于微服务架构。
    • LXC更适合需要更多控制和自定义配置的容器场景,通常用于虚拟化和多租户环境。

总结:
Docker是一个高级容器管理工具,更适用于快速构建、部署和管理容器化应用程序。它提供了易于使用的接口和广泛的生态系统。LXC是一种更低级别的容器技术,通常需要更多的手动配置和管理,适用于需要更多自定义控制的情况。选择哪种技术取决于具体需求和项目的要求。

3.32 Docker与Vagrant有何不同

DockerVagrant都是用于虚拟化和容器化的工具,但它们在一些方面有很大的不同:

  1. 虚拟化级别:
    • Docker是一种容器化技术,它使用Linux容器(如Docker容器)来实现轻量级虚拟化。容器共享主机操作系统内核,因此更轻量、更快速,但隔离性较低。
    • Vagrant是一种虚拟机(VM)管理工具,它使用虚拟化技术(如VirtualBoxVMware)来创建和管理虚拟机。虚拟机是完整的操作系统实例,因此更重量级,但隔离性更强。
  2. 隔离性和安全性:
    • Docker容器之间的隔离性相对较低,因为它们共享主机操作系统内核。这意味着容器之间可以共享一些资源和潜在的安全风险。
    • 虚拟机之间的隔离性较高,因为它们各自运行独立的操作系统内核。虚拟机提供了更强的安全性和隔离,适用于多租户环境。
  3. 资源利用率:
    • Docker容器通常比虚拟机消耗更少的资源,因为它们共享主机操作系统内核,并且不需要运行多个完整的操作系统。
    • 虚拟机通常需要更多的资源,因为它们运行独立的操作系统内核,包括内存、磁盘空间和CPU
  4. 生态系统和用途:
    • Docker拥有庞大的容器生态系统,适用于快速构建、部署和管理容器化应用程序。它通常用于微服务架构和持续集成/持续交付(CI/CD)流程。
    • Vagrant主要用于创建和管理虚拟机,可以用于开发环境的快速设置和复制,以及为开发团队提供一致的开发环境。
  5. 配置管理:
    • Docker容器通常使用Dockerfile来定义容器的构建过程和环境配置。
    • Vagrant使用Vagrantfile来定义虚拟机的配置和启动过程。
  6. 性能:
    • Docker容器通常启动更快,因为它们轻量级且不需要启动完整的操作系统。
    • 虚拟机启动可能需要更多时间,因为它们需要启动整个操作系统。

总结:
DockerVagrant在虚拟化和容器化方面有不同的设计目标和适用场景。选择取决于需求,如果需要轻量级、高性能的容器化解决方案,可以选择Docker。如果需要创建和管理虚拟机,并提供一致的开发环境,可以选择Vagrant。在某些情况下,这两者也可以结合使用,例如在Vagrant虚拟机中运行Docker容器。

3.33 开发环境中Docker与Vagrant该如何选择

在选择开发环境中使用Docker还是Vagrant时,需要考虑具体需求和项目的特点。以下是一些考虑因素,可以帮助做出决策:

使用Docker的情况:

  1. 容器化应用程序:如果正在开发、测试或部署容器化的应用程序,那么Docker是一个理想的选择。Docker容器提供了轻量级、可移植和一致的运行环境,可以轻松在不同的开发、测试和生产环境中进行部署。
  2. 微服务架构:如果应用程序采用微服务架构,Docker容器可以帮助将不同的微服务独立打包为容器,并在开发环境中以容器的形式运行它们,以更好地模拟生产环境。
  3. CI/CD流程Docker容器在持续集成和持续交付(CI/CD)流程中非常有用,可以确保开发、测试和部署过程的一致性。
  4. 资源效率Docker容器通常比虚拟机更轻量级,可以更有效地使用资源,减少开发环境的资源开销。

使用Vagrant的情况:

  1. 多虚拟机环境:如果需要在开发环境中使用多个独立的虚拟机,并希望每个虚拟机具有自己的操作系统内核和独立的环境,那么Vagrant是一个不错的选择。这对于复杂的开发和测试场景非常有用。
  2. 一致的开发环境Vagrant可以帮助确保整个团队使用相同的虚拟机配置,以便在不同的开发环境之间保持一致性。
  3. 集成虚拟机和容器:在某些情况下,可能希望在Vagrant虚拟机中运行Docker容器,以结合两者的优势。Vagrant提供了与虚拟机的集成能力。
  4. 较大的资源需求:如果开发环境需要更多的计算资源(例如内存或CPU),或者需要更复杂的网络配置,那么Vagrant的虚拟机可以提供更大的灵活性。

最终,选择使用Docker还是Vagrant取决于项目的需求、团队的偏好以及目标。在某些情况下,甚至可以将它们结合使用,例如在Vagrant虚拟机中运行Docker容器来组合两者的优势。无论如何,确保开发环境满足项目需求,并且易于维护和管理。

3.34 如何将一台宿主机的docker环境迁移到另外一台宿主机

在源宿主机上备份Docker数据:使用Docker提供的工具或手动备份需要的Docker数据,包括镜像、容器、卷、网络设置等。

  1. 备份Docker镜像:可以使用docker save命令将镜像导出为tar文件。例如:docker save -o my_images.tar
  2. 备份Docker容器:如果有自定义容器配置,可以将其导出为Docker Compose文件或Dockerfile,以便在新宿主机上重新创建容器。
  3. 备份Docker卷:使用docker cp命令将卷中的数据复制到宿主机上,并将其备份。

在目标宿主机上还原Docker数据:将从源宿主机备份的Docker数据还原到相应的位置。

  1. 还原Docker镜像:可以使用docker load命令将备份的镜像加载到新宿主机上。例如:docker load -i my_images.tar
  2. 配置Docker容器:如果备份了自定义容器配置,使用Docker Compose文件或Dockerfile重新创建容器。
  3. 还原Docker卷:将备份的卷数据复制到新宿主机上的卷目录,并在容器中挂载它们。

配置Docker环境:确保目标宿主机上已安装Docker,并根据需要进行配置,以使其与源宿主机上的Docker环境相似(例如,网络设置、存储驱动程序等)。

测试和验证:在目标宿主机上启动容器,验证它们是否按预期运行。检查日志和应用程序的功能,确保一切正常。

注意:
Docker环境的迁移可能涉及到一些复杂性,特别是在不同的宿主机上,可能存在配置差异。因此,在进行迁移之前,建议仔细计划和测试,以确保迁移顺利进行,并且应用程序在新宿主机上正常工作。

此外,如果使用的是Docker SwarmKubernetes等容器编排工具,还需要迁移相关配置和状态信息,以确保集群的连续性。每个工具都有相应的迁移和备份方案,具体取决于部署情况。

3.35 Docker镜像联合文件系统

Docker镜像联合文件系统(Union File System)是Docker中一个重要的概念,它用于构建和管理Docker镜像。联合文件系统是一种文件系统层叠的技术,它允许多个文件系统层叠在一起,以创建一个单一的文件系统视图。

Docker使用联合文件系统来构建和管理镜像的多个层。每个Docker镜像都由多个层(Layers)组成,每个层代表一组文件或文件的更改。这些层按顺序堆叠在一起,形成一个完整的文件系统,使得Docker容器可以在这个文件系统上运行。

以下是联合文件系统的一些关键特点和概念:

  1. :每个Docker镜像都由多个层组成,每个层包含文件系统中的一组文件或文件的更改。层是不可变的,一旦创建就不能修改。
  2. 分层构建Docker镜像是通过分层构建的,每个层都基于前一个层进行更改。这使得构建和推送镜像时只需要传输更改的部分,从而节省带宽和存储空间。
  3. 联合挂载(Union MountDocker容器在运行时使用联合挂载技术将这些层堆叠在一起,以创建一个可写的容器文件系统。这使得容器可以具有自己的文件系统视图,但仍然共享相同的基础层。
  4. 容器层:每个容器都有一个额外的可写层,称为容器层。这个层用于存储容器内部的文件更改,使得容器可以在运行时修改文件系统,而不会影响基础镜像。
  5. 镜像的不可变性Docker镜像的层是不可变的,这意味着一旦构建,就不能修改。任何对镜像的更改都会创建一个新的镜像层。
  6. 共享层:多个镜像可以共享相同的层,这可以显著减少磁盘空间的占用,因为相同的文件层只需要存储一次。

联合文件系统的使用使Docker成为一种轻量级和高效的容器化技术,允许快速创建和部署容器,同时最大限度地减少存储和带宽资源的使用。理解这个概念有助于更好地理解Docker镜像的构建和运行机制。

3.36 Docker是安全的么

Docker本身提供了一些安全机制和隔离措施,但它的安全性取决于如何正确配置和使用它。以下是一些关于Docker安全性的重要考虑因素:

  1. 隔离Docker使用Linux的命名空间(namespace)和控制组(cgroup)等功能来提供容器间的隔离。这些隔离机制确保容器之间和容器与宿主机之间的资源隔离。但需要注意的是,虽然Docker提供了良好的隔离,但不是绝对的安全隔离。
  2. 容器漏洞:容器化应用程序的安全性与容器内部的操作系统和应用程序有关。如果容器内部的操作系统或应用程序存在漏洞,攻击者可能会利用这些漏洞来攻击容器。因此,保持容器内的操作系统和应用程序的安全性非常重要。
  3. 映像来源:使用来自可信来源的Docker镜像是至关重要的。不要使用未经验证的或来自不可信来源的镜像,因为它们可能包含恶意软件或安全漏洞。
  4. 镜像审查:在使用外部镜像之前,最好审查它们的Dockerfile和构建过程,以确保它们不包含不必要的组件或潜在的安全问题。
  5. 最小权限原则:在运行容器时,尽量减少容器的权限,避免将宿主机的敏感信息直接映射到容器中。只赋予容器运行所需的最低权限。
  6. Docker安全工具:有一些Docker安全工具和服务可用于扫描容器映像,检测潜在的漏洞和安全问题。例如,可以使用容器扫描工具来审查镜像并确保其安全。
  7. 漏洞修复和升级:定期更新Docker守护程序和Docker引擎以获取安全更新。同时,定期更新和维护容器内的操作系统和应用程序以修复已知的漏洞。

总结:
Docker可以提供一定程度的安全性,但安全性的最终责任在于容器的构建和运行。使用Docker时,需要采取一系列安全最佳实践,并确保跟踪容器内部的安全问题。合理配置和维护Docker环境可以大大提高安全性。

3.37 如何清理后台停止的容器

要清理后台停止的容器,可以使用docker container prune命令。这个命令将删除所有处于停止状态的容器,以释放磁盘空间和资源。以下是如何使用该命令的步骤:

  1. 打开终端或命令行界面。
  2. 运行以下命令来清理后台停止的容器:docker container prune
  3. 系统将显示一条警告消息,提示确认是否要删除容器。如果确定,请输入y或yes,然后按Enter键。
    WARNING! This will remove all stopped containers.
    Are you sure you want to continue? [y/N]
    
  4. Docker将开始删除所有已停止的容器。一旦完成,将收到一条消息,显示已删除的容器数量。
    Deleted Containers:
    <container_id_1>
    <container_id_2>
    ...
    
    请注意,docker container prune命令将删除所有已停止的容器,包括以前运行的容器。如果只想删除特定容器,可以使用docker container rm命令,后跟容器的名称或ID。例如:
    docker container rm <container_id_or_name>
    

确保谨慎使用这些命令,以免意外删除重要的容器。在删除容器之前,请确保不再需要它们,并备份任何重要的数据。

3.38 当启动容器的时候提示:exec format error?如何解决问题

"exec format error"错误通常发生在尝试在不兼容的体系结构上运行容器时。这可能是由于容器镜像与宿主机的CPU架构不匹配所致。要解决这个问题,可以采取以下步骤:

  1. 检查宿主机的CPU架构:确保宿主机的CPU架构与容器镜像的期望CPU架构相匹配。可以使用以下命令查看宿主机的CPU架构:uname -m,然后,检查容器镜像是否适用于该架构。
  2. 使用适用于宿主机的容器镜像:如果宿主机和容器镜像的CPU架构不匹配,需要使用适用于宿主机的容器镜像。通常,Docker Hub等镜像仓库提供了多个不同的架构版本的容器镜像,以满足不同的需求。
  3. 切换宿主机架构:如果宿主机和容器镜像的CPU架构不匹配,可以考虑切换到适用于容器的CPU架构的宿主机。请注意,这可能需要更换硬件或使用虚拟化等技术来模拟所需的CPU架构。
  4. 构建自定义镜像:如果无法找到适用于宿主机的容器镜像,可以尝试构建自定义的容器镜像,以适应宿主机架构。这涉及到创建一个Dockerfile,并确保在Dockerfile中选择了正确的基础镜像和架构。
  5. 检查Docker版本:确保Docker版本是最新的,以获取对不同架构的更好支持。较旧的Docker版本可能不支持某些架构。

总结:
要解决"exec format error"错误,需要确保容器镜像与宿主机的CPU架构匹配,并且选择适用于宿主机的镜像。如果无法找到适合的容器镜像,可能需要考虑更改宿主机架构或自定义构建容器镜像。

3.39 如何退出一个镜像的bash,而不终止它

要退出一个正在运行的容器的bash终端,而不终止容器本身,可以使用以下方法之一:

  1. 使用Ctrl + P,Ctrl + Q:如果在容器的bash终端中,可以使用键盘快捷键Ctrl + P,然后Ctrl + Q来分离终端,而不终止容器。这会将返回到宿主机的终端,而容器继续运行。
  2. 使用"docker exec"命令:如果使用了docker exec命令进入容器的bash终端,可以按Ctrl + D来退出容器的bash终端,而不终止容器本身。这将断开与容器的连接,但容器将继续运行。例如:docker exec -it bash
  3. 使用"screen"或"tmux":如果在容器内使用了"screen""tmux"等终端多路复用工具,可以通过分离"screen""tmux"会话来退出容器的bash终端,容器将继续运行。

注意:
以上方法中的一些可能需要首先进入容器的bash终端。如果正在运行一个交互式容器(例如,通过docker run -it),可以直接退出bash终端,而不终止容器。如果只是想退出一个后台运行的容器的bash终端,可以使用docker exec命令或Ctrl + PCtrl + Q键盘快捷键。

3.40 如何退出容器时候自动删除

要在退出容器时自动删除容器,可以使用docker run命令的--rm选项。这个选项告诉Docker在容器退出后自动删除容器实例,而不需要手动清理。如何使用这个选项的示例:docker run --rm ,在这个命令中,--rm选项告诉Docker在容器退出后删除它。只需替换为要运行的容器镜像的名称或ID

这对于一次性任务或不需要保留容器实例的情况非常有用。容器退出后,相关的资源和数据将被清理,不会留下残留容器。

3.41 Docker里面如何做监控?

如果我的应用做成容器化去部署,我怎么去监控应用这个运行正常它的性能指标它的一些状态。

  1. Docker StatsDocker提供了一个内置的docker stats命令,可以实时查看运行中容器的资源使用情况,包括CPU、内存、网络和磁盘等。例如:
docker stats container_name
  1. PrometheusPrometheus是一个流行的开源监控解决方案,可以与容器集成。使用Prometheus,可以采集容器的各种指标,并进行报警、图形化展示等操作。需要在容器中运行Prometheus的代理(例如node_exporter)来收集指标数据。
  2. cAdvisorGoogle提供的cAdvisor是一个容器监控工具,可以收集有关容器的CPU、内存、磁盘和网络等性能指标。cAdvisor可以与Docker结合使用,提供实时监控和历史数据。
docker run -v /:/rootfs:ro -v /var/run:/var/run:ro -v /sys:/sys:ro -v /var/lib/docker/:/var/lib/docker:ro -p 8080:8080 --detach=true --name=cadvisor google/cadvisor:latest
  1. Docker内置Health ChecksDocker支持容器的健康检查。通过在Dockerfile中使用HEALTHCHECK指令,可以定义容器的健康检查命令。这样,在Docker运行时,可以使用docker inspect查看容器的健康状况。
FROM nginx

HEALTHCHECK --interval=5s --timeout=3s \
  CMD curl -f http://localhost/ || exit 1
  1. ELK Stack(Elasticsearch, Logstash, Kibana):对容器日志进行集中管理和监控也是一种常见做法。使用ELK Stack,可以将容器的日志集中到Elasticsearch中,并使用Kibana进行可视化展示和搜索。 Logstash可以用于数据的过滤和处理。

这些方法可以组合使用,根据具体的监控需求和环境来选择。通过综合使用这些监控工具,可以有效地监测和管理Docker容器的运行状态。

3.42 Docker容器的项目怎么去做一个上线升级替换?

Docker部署的项目中,进行上线升级替换通常需要考虑以下步骤和策略,以确保服务的高可用性和零宕机时间:

  1. 准备新版本镜像:确保新版本的Docker镜像已经构建,并且在本地或远程Docker仓库中可用。确保新版本的镜像在测试环境中已经通过了验证。
  2. 备份和持久化数据:如果应用程序使用了持久化数据(例如数据库),确保在升级之前进行备份,并考虑数据迁移和升级方案。
  3. 版本控制和回滚策略:在进行升级之前,确保使用版本控制工具(例如 Git)对代码进行标记。定义回滚策略,以防升级出现问题时能够迅速回滚到之前的版本。
  4. 流量切换:在进行升级之前,可以使用流量切换策略,逐渐将流量从旧版本切换到新版本。这可以通过服务代理或负载均衡器来实现,确保流量平滑过渡。
  5. Blue-Green部署:采用Blue-Green部署策略,即在生产环境中同时维护两个环境,一个是当前运行的(Blue),另一个是新版本的(Green)。通过负载均衡器逐步将流量从Blue切换到Green,完成升级。这样可以降低风险,如果新版本有问题,可以快速切回到旧版本。
  6. 零宕机升级:如果对服务不允许有任何宕机时间,可以采用零宕机升级策略。这包括在容器编排工具(如KubernetesDocker Swarm)中使用滚动更新策略,逐个替换服务实例。也可以使用进程重启策略,通过平滑重启来替换服务。
  7. 健康检查和监控:在升级期间,使用健康检查工具确保新版本服务的正常运行。同时,通过监控工具实时监测服务的性能和健康状态。
  8. 升级后的测试:升级完成后,进行全面的功能测试、性能测试和回归测试,确保新版本的服务正常工作。
  9. 回滚操作:如果升级过程中发现问题,确保有可靠的回滚方案。这可能包括还原代码、还原数据、回滚数据库变更等操作。
  10. 文档和通知:在升级之前,更新文档,包括新版本的特性、改动和注意事项。并通知团队成员和相关利益相关者关于升级计划和时间。

以上策略和步骤可以根据具体项目和环境的特点进行调整和优化。在进行升级之前,充分的测试和备份是确保升级成功的重要步骤。

4 K8S(V1.28)

参考1:Kubernetes中文官网
参考2:面试之—K8S、Docker面试题整理

官方介绍
Kubernetes也称为K8S,是用于自动部署、扩缩和管理容器化应用程序的开源系统。

Kubernetes是一个可移植、可扩展的开源平台,用于管理容器化的工作负载和服务,方便进行声明式配置和自动化。Kubernetes拥有一个庞大且快速增长的生态系统,其服务、支持和工具的使用范围广泛。

通俗理解Kubernetes是一个编排容器的工具,其实也是管理应用的全生命周期的一个工具,从创建应用,应用的部署,应用提供服务,扩容缩容应用,应用更新,都非常的方便,而且可以做到故障自愈,例如一个服务器挂了,可以自动将这个服务器上的服务调度到另外一个主机上进行运行,无需进行人工干涉。

4.1 Kubernetes特性

  1. 自动化上线和回滚
    Kubernetes会分步骤地将针对应用或其配置的更改上线,同时监视应用程序运行状况以确保你不会同时终止所有实例。如果出现问题,Kubernetes会为你回滚所作更改。你应该充分利用不断成长的部署方案生态系统。
  2. 服务发现与负载均衡
    你无需修改应用来使用陌生的服务发现机制。Kubernetes为每个Pod提供了自己的IP地址并为一组Pod提供一个DNS名称,并且可以在它们之间实现负载均衡。
  3. 自我修复
    重新启动失败的容器,在节点死亡时替换并重新调度容器, 杀死不响应用户定义的健康检查的容器, 并且在它们准备好服务之前不会将它们公布给客户端。
  4. 存储编排
    自动挂载所选存储系统,包括本地存储、公有云提供商所提供的存储或者诸如iSCSINFS这类网络存储系统。
  5. Secret 和配置管理
    部署和更新Secret和应用程序的配置而不必重新构建容器镜像, 且不必将软件堆栈配置中的秘密信息暴露出来。
  6. 自动装箱
    根据资源需求和其他限制自动放置容器,同时避免影响可用性。 将关键性的和尽力而为性质的工作负载进行混合放置,以提高资源利用率并节省更多资源。
  7. 批量执行
    除了服务之外,Kubernetes还可以管理你的批处理和CI工作负载,在期望时替换掉失效的容器。
  8. IPv4/IPv6 双协议栈
    PodService分配IPv4IPv6地址。
  9. 水平扩缩
    使用一个简单的命令、一个UI或基于CPU使用情况自动对应用程序进行扩缩。
  10. 为扩展性设计
    无需更改上游源码即可扩展你的Kubernetes集群。

4.2 为什么需要Kubernetes,它能做什么

参考1:为什么需要Kubernetes,它能做什么?(官方解释)

  1. 服务发现和负载均衡
    Kubernetes可以使用DNS名称或自己的IP地址来曝露容器。 如果进入容器的流量很大, Kubernetes可以负载均衡并分配网络流量,从而使部署稳定。
  2. 存储编排
    Kubernetes允许你自动挂载你选择的存储系统,例如本地存储、公共云提供商等。
  3. 自动部署和回滚
    你可以使用Kubernetes描述已部署容器的所需状态, 它可以以受控的速率将实际状态更改为期望状态。 例如,你可以自动化Kubernetes来为你的部署创建新容器, 删除现有容器并将它们的所有资源用于新容器。
  4. 自动完成装箱计算
    你为Kubernetes提供许多节点组成的集群,在这个集群上运行容器化的任务。 你告诉Kubernetes每个容器需要多少CPU和内存 (RAM)。 Kubernetes可以将这些容器按实际情况调度到你的节点上,以最佳方式利用你的资源。
  5. 自我修复
    Kubernetes将重新启动失败的容器、替换容器、杀死不响应用户定义的运行状况检查的容器, 并且在准备好服务之前不将其通告给客户端。
  6. 密钥与配置管理
    Kubernetes允许你存储和管理敏感信息,例如密码、OAuth令牌和ssh密钥。 你可以在不重建容器镜像的情况下部署和更新密钥和应用程序配置,也无需在堆栈配置中暴露密钥。

※ 4.3~4.6 都是概念解释,和官网内容一致

4.3 Kubernetes对象

4.3.1 Kubernetes对象

参考:Kubernetes 对象

4.3.1.1 理解Kubernetes对象

Kubernetes系统中,Kubernetes对象是持久化的实体。 Kubernetes使用这些实体去表示整个集群的状态。 比较特别地是,它们描述了如下信息:

  • 哪些容器化应用正在运行(以及在哪些节点上运行)。
  • 可以被应用使用的资源。
  • 关于应用运行时表现的策略,比如重启策略、升级策略以及容错策略。

Kubernetes对象是一种“意向表达(Record of Intent)”。一旦创建该对象,Kubernetes系统将不断工作以确保该对象存在。通过创建对象,你就是在告知Kubernetes系统,你想要的集群工作负载状态看起来应是什么样子的, 这就是Kubernetes集群所谓的 期望状态(Desired State)

操作Kubernetes对象 —— 无论是创建、修改或者删除 —— 需要使用Kubernetes API。 比如,当使用kubectl命令行接口(CLI)时,CLI会调用必要的Kubernetes API; 也可以在程序中使用客户端库, 来直接调用Kubernetes API

对象规约(Spec)与状态(Status)
每个Kubernetes对象包含两个嵌套的对象字段,它们负责管理对象的配置: 对象spec(规约)和对象status(状态)。对于具有spec的对象,你必须在创建对象时设置其内容,描述你希望对象所具有的特征: 期望状态(Desired State)

status描述了对象的当前状态(Current State),它是由Kubernetes系统和组件设置并更新的。 在任何时刻,Kubernetes控制平面 都一直都在积极地管理着对象的实际状态,以使之达成期望状态

例如,Kubernetes中的Deployment对象能够表示运行在集群中的应用。 当创建Deployment时,可能会去设置Deploymentspec,以指定该应用要有3个副本运行。 Kubernetes系统读取Deploymentspec, 并启动我们所期望的应用的3个实例 —— 更新状态以与规约相匹配。 如果这些实例中有的失败了(一种状态变更),Kubernetes系统会通过执行修正操作来响应spec和状态间的不一致 —— 意味着它会启动一个新的实例来替换。

描述Kubernetes对象
创建Kubernetes对象时,必须提供对象的spec,用来描述该对象的期望状态,以及关于对象的一些基本信息(例如名称)。 当使用 Kubernetes API创建对象时(直接创建,或经由kubectl), API请求必须在请求本体中包含JSON格式的信息。 大多数情况下,你需要提供.yaml文件为kubectl提供这些信息。 kubectl在发起API请求时,将这些信息转换成JSON格式。

这里有一个.yaml示例文件,展示了Kubernetes Deployment的必需字段和对象spec

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2 # 告知 Deployment 运行 2 个与该模板匹配的 Pod
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

相较于上面使用.yaml文件来创建Deployment,另一种类似的方式是使用kubectl命令行接口(CLI)中的kubectl apply命令, 将.yaml文件作为参数。下面是一个示例:

kubectl apply -f https://k8s.io/examples/application/deployment.yaml

输出类似下面这样:

deployment.apps/nginx-deployment created

必需字段
在想要创建的Kubernetes对象所对应的.yaml文件中,需要配置的字段如下:

  1. apiVersion:创建该对象所使用的Kubernetes API的版本。
  2. kind:想要创建的对象的类别。
  3. metadata:帮助唯一标识对象的一些数据,包括一个name字符串、UID和可选的namespace
  4. spec:你所期望的该对象的状态。

对每个Kubernetes对象而言,其spec之精确格式都是不同的,包含了特定于该对象的嵌套字段。 我们能在Kubernetes API参考找到我们想要在Kubernetes上创建的任何对象的规约格式。

例如,参阅Pod API参考文档中spec字段。 对于每个Pod,其.spec字段设置了Pod及其期望状态(例如Pod中每个容器的容器镜像名称)。 另一个对象规约的例子是StatefulSet API中的spec字段。 对于StatefulSet而言,其.spec字段设置了StatefulSet及其期望状态。 在StatefulSet.spec内,有一个为Pod对象提供的模板。 该模板描述了StatefulSet控制器为了满足StatefulSet规约而要创建的Pod。 不同类型的对象可以有不同的.status信息。API参考页面给出了.spec字段的详细结构, 以及针对不同类型API对象的具体内容。

说明
请查看配置最佳实践来获取有关编写YAML配置文件的更多信息。

4.3.1.2 服务器端字段验证

Kubernetes v1.25开始,API服务器提供了服务器端字段验证, 可以检测对象中未被识别或重复的字段。它在服务器端提供了 kubectl --validate的所有功能。

kubectl工具使用--validate标志来设置字段验证级别。它接受值ignorewarnstrict,同时还接受值true(等同于strict)和false(等同于ignore)。kubectl的默认验证设置为--validate=true

  • Strict:严格的字段验证,验证失败时会报错
  • Warn:执行字段验证,但错误会以警告形式提供而不是拒绝请求
  • Ignore:不执行服务器端字段验证

kubectl无法连接到支持字段验证的API服务器时,它将回退为使用客户端验证。 Kubernetes 1.27及更高版本始终提供字段验证;较早的Kubernetes版本可能没有此功能。 如果你的集群版本低于v1.27,可以查阅适用于你的Kubernetes版本的文档。

4.3.2 Kubernetes 对象管理

参考:Kubernetes 对象管理

4.3.3 对象名称和 ID

参考:对象名称和 ID

4.3.4 标签和选择算符

参考:标签和选择算符

4.3.5 NameSpace

参考:NameSpace

4.3.6 注解

参考:注解

4.3.7 字段选择器

参考:字段选择器

4.3.8 Finalizers

参考:Finalizers

4.3.9 属主与附属

参考:属主与附属

4.3.10 推荐使用的标签

参考:推荐使用的标签

4.4 Kubernetes组件

参考:Kubernetes 组件(官方解释)

注意Kubernetes是一个集群。

当部署完Kubernetes,便拥有了一个完整的集群。一组工作机器,称为节点, 会运行容器化应用程序。每个集群至少有一个工作节点。

工作节点会托管Pod,而Pod就是作为应用负载的组件。 控制平面管理集群中的工作节点和Pod。 在生产环境中,控制平面通常跨多台计算机运行, 一个集群通常运行多个节点,提供容错性和高可用性。

Kubernetes集群分为两部分:

  1. 左侧的控制平面(Control Plane)组件:控制平面管理集群中的工作节点和Pod
  2. 右侧的工作节点(Node:一组工作机器,称为节点, 会运行容器化应用程序。每个集群至少有一个工作节点。工作节点会托管Pod ,而Pod就是作为应用负载的组件。
    K8S集群组件图

4.4.1 控制平面组件(Control Plane Components)

参考:控制平面组件(Control Plane Components)(官方解释)

控制平面组件会为集群做出全局决策,比如资源的调度。 以及检测和响应集群事件,例如当不满足部署的 replicas 字段时, 要启动新的 pod)。

控制平面组件可以在集群中的任何节点上运行。 然而,为了简单起见,设置脚本通常会在同一个计算机上启动所有控制平面组件, 并且不会在此计算机上运行用户容器。

控制平面组件的构成

  1. kube-apiserver
  2. etcd
  3. kube-scheduler
  4. kube-controller-manager
  5. cloud-controller-manager【可选】
4.4.1.1 kube-apiserver

API服务器是Kubernetes控制平面的组件,kube-apiserver负责公开了Kubernetes API,负责处理接受请求的工作。 API服务器是Kubernetes控制平面的前端。

Kubernetes API服务器的主要实现是kube-apiserverkube-apiserver设计上考虑了水平扩缩,也就是说,它可通过部署多个实例来进行扩缩。 你可以运行kube-apiserver的多个实例,并在这些实例之间平衡流量。

4.4.1.2 etcd

一致且高度可用的键值存储,用作Kubernetes的所有集群数据的后台数据库。如果你的Kubernetes集群使用etcd作为其后台数据库, 请确保你针对这些数据有一份备份计划。

4.4.1.3 kube-scheduler

kube-scheduler是控制平面的组件,负责监视新创建的、未指定运行节点(node)的Pods, 并选择节点来让Pod在上面运行。

调度决策考虑的因素包括单个PodPods集合的资源需求、软硬件及策略约束、 亲和性及反亲和性规范、数据位置、工作负载间的干扰及最后时限。

4.4.1.4 kube-controller-manager

kube-controller-manager是控制平面的组件,负责运行控制器进程。从逻辑上讲, 每个控制器都是一个单独的进程, 但是为了降低复杂性,它们都被编译到同一个可执行文件,并在同一个进程中运行。

这些控制器包括:

  1. 节点控制器(Node Controller):负责在节点出现故障时进行通知和响应。
  2. 任务控制器(Job Controller):监测代表一次性任务的Job对象,然后创建Pods来运行这些任务直至完成。
  3. 端点控制器(Endpoints Controller):填充端点(Endpoints)对象(即加入ServicePods)。
  4. 服务帐户和令牌控制器(Service Account & Token Controllers):为新的命名空间创建默认帐户和API访问令牌。
4.4.1.5 cloud-controller-manager【可选】

一个Kubernetes控制平面组件,嵌入了特定于云平台的控制逻辑。 云控制器管理器(Cloud Controller Manager)允许你将你的集群连接到云提供商的API之上, 并将与该云平台交互的组件同与你的集群交互的组件分离开来。

cloud-controller-manager 仅运行特定于云平台的控制器。 因此如果你在自己的环境中运行Kubernetes,或者在本地计算机中运行学习环境, 所部署的集群不需要有云控制器管理器。

kube-controller-manager 类似,cloud-controller-manager 将若干逻辑上独立的控制回路组合到同一个可执行文件中, 供你以同一进程的方式运行。 你可以对其执行水平扩容(运行不止一个副本)以提升性能或者增强容错能力。

下面的控制器都包含对云平台驱动的依赖:

  1. 节点控制器(Node Controller):用于在节点终止响应后检查云提供商以确定节点是否已被删除。
  2. 路由控制器(Route Controller):用于在底层云基础架构中设置路由。
  3. 服务控制器(Service Controller):用于创建、更新和删除云提供商负载均衡器。

4.4.2 Node组件

参考:Node 组件(官方解释)

节点组件会在每个节点上运行,负责维护运行的Pods并提供Kubernetes运行环境。

Node 组件的构成

  1. kubelet
  2. kube-proxy
  3. 容器运行时(Container Runtime)
4.4.2.1 kubelet

kubelet会在集群中每个节点(node)上运行。 它保证容器(containers)都运行在Pods中。

kubelet接收一组通过各类机制提供给它的PodSpecs, 确保这些PodSpecs中描述的容器处于运行状态且健康。 kubelet不会管理不是由Kubernetes创建的容器。

4.4.2.2 kube-proxy

kube-proxy是集群中每个节点(node)所上运行的网络代理, 实现Kubernetes服务(Service) 概念的一部分。

kube-proxy维护节点上的一些网络规则, 这些网络规则会允许从集群内部或外部的网络会话与Pods进行网络通信。

如果操作系统提供了可用的数据包过滤层,则kube-proxy会通过它来实现网络规则。 否则,kube-proxy仅做流量转发。

4.4.2.3 容器运行时(Container Runtime)

容器运行环境是负责运行容器的软件。Kubernetes支持许多容器运行环境,例如containerdCRI-O以及Kubernetes CRI (容器运行环境接口) 的其他任何实现。

4.5 插件(Addons)

参考:插件(Addons)(官方解释)

插件使用Kubernetes资源(DaemonSetDeployment等)实现集群功能。 因为这些插件提供集群级别的功能,插件中命名空间域的资源属于kube-system命名空间。

插件(Addons)组件的构成

  1. DNS
  2. Web界面(仪表盘)
  3. 容器资源监控
  4. 集群层面日志

4.5.1 DNS

尽管其他插件都并非严格意义上的必需组件,但几乎所有Kubernetes集群都应该有集群DNS, 因为很多示例都需要DNS服务。

集群DNS是一个DNS服务器,和环境中的其他DNS服务器一起工作,它为Kubernetes服务提供DNS记录。

Kubernetes启动的容器自动将此DNS服务器包含在其DNS搜索列表中。

4.5.2 Web 界面(仪表盘)

DashboardKubernetes集群的通用的、基于Web的用户界面。 它使用户可以管理集群中运行的应用程序以及集群本身, 并进行故障排除。

4.5.3 容器资源监控

容器资源监控是将关于容器的一些常见的时间序列度量值保存到一个集中的数据库中, 并提供浏览这些数据的界面。

4.5.4 集群层面日志

集群层面日志机制负责将容器的日志数据保存到一个集中的日志存储中, 这种集中日志存储提供搜索和浏览接口。

4.6 Kubernetes API

参考:Kubernetes API(官方解释)

Kubernetes控制面的核心是API服务器。 API服务器负责提供HTTP API,以供用户集群中的不同部分和集群外部组件相互通信。

Kubernetes API使你可以查询和操纵Kubernetes API中对象(例如:PodNamespaceConfigMapEvent)的状态。

大部分操作都可以通过kubectl命令行接口或类似kubeadm这类命令行工具来执行, 这些工具在背后也是调用API。不过,你也可以使用 REST调用来访问这些API

如果你正在编写程序来访问Kubernetes API, 可以考虑使用客户端库之一。

4.6.1 OpenAPI 规范

OpenAPI V2
Kubernetes API服务器通过/openapi/v2端点提供聚合的OpenAPI v2规范。 你可以按照下表所给的请求头部,指定响应的格式

头部 可选值 说明
Accept-Encoding gzip 不指定此头部也是可以的
Accept application/[email protected]+protobuf 主要用于集群内部
Accept application/json 默认值
Accept * 提供application/json

KubernetesAPI实现了一种基于Protobuf的序列化格式,主要用于集群内部通信。 关于此格式的详细信息,可参考Kubernetes Protobuf序列化设计提案。 每种模式对应的接口描述语言(IDL)位于定义API对象的Go包中。

OpenAPI V3
特性状态:Kubernetes v1.27 [stable]

Kubernetes支持将其API的描述以OpenAPI v3形式发布。

发现端点/openapi/v3被提供用来查看可用的所有组版本列表。 此列表仅返回JSON。这些组、版本以下面的格式提供:

{
    "paths": {
        ...,
        "api/v1": {
            "serverRelativeURL": "/openapi/v3/api/v1?hash=CC0E9BFD992D8C59AEC98A1E2336F899E8318D3CF4C68944C3DEC640AF5AB52D864AC50DAA8D145B3494F75FA3CFF939FCBDDA431DAD3CA79738B297795818CF"
        },
        "apis/admissionregistration.k8s.io/v1": {
            "serverRelativeURL": "/openapi/v3/apis/admissionregistration.k8s.io/v1?hash=E19CC93A116982CE5422FC42B590A8AFAD92CDE9AE4D59B5CAAD568F083AD07946E6CB5817531680BCE6E215C16973CD39003B0425F3477CFD854E89A9DB6597"
        },
        ....
    }
}

为了改进客户端缓存,相对的URL会指向不可变的OpenAPI描述。 为了此目的,API服务器也会设置正确的HTTP缓存标头 (Expires 为未来1年,和 Cache-Controlimmutable)。 当一个过时的URL被使用时,API服务器会返回一个指向最新URL的重定向。

Kubernetes API服务器会在端点/openapi/v3/apis//?hash=发布一个Kubernetes组版本的OpenAPI v3规范。

请参阅下表了解可接受的请求头部。

头部 可选值 说明
Accept-Encoding gzip 不指定此头部也是可以的
Accept application/[email protected]+protobuf 主要用于集群内部
Accept application/json 默认值
Accept * 提供application/json

k8s.io/client-go/openapi3包中提供了获取OpenAPI v3Golang实现。

4.6.2 持久化

Kubernetes通过将序列化状态的对象写入到etcd中完成存储操作。

4.6.3 API 发现

集群支持的所有组版本列表被发布在/api/apis端点。 每个组版本还会通过/apis// (例如 /apis/rbac.authorization.k8s.io/v1alpha1)广播支持的资源列表。 这些端点由kubectl用于获取集群支持的资源列表。

聚合发现
特性状态Kubernetes v1.27 [beta]
Kubernetes对聚合发现提供Beta支持,通过两个端点(/api/apis) 发布集群支持的所有资源,而不是每个组版本都需要一个端点。 请求此端点显著减少了获取平均Kubernetes集群发现而发送的请求数量。 通过请求各自的端点并附带表明聚合发现资源Accept: application/json;v=v2beta1;g=apidiscovery.k8s.io;as=APIGroupDiscoveryListAccept头部来进行访问。

该端点还支持ETagprotobuf编码。

4.6.4 API组和版本控制

为了更容易消除字段或重组资源的呈现方式,Kubernetes支持多个API版本,每个版本位于不同的API路径, 例如/api/v1/apis/rbac.authorization.k8s.io/v1alpha1

版本控制是在API级别而不是在资源或字段级别完成的,以确保API呈现出清晰、一致的系统资源和行为视图, 并能够控制对生命结束和/或实验性API的访问。

为了更容易演进和扩展其APIKubernetes实现了API组, 这些API组可以被启用或禁用。

API 资源通过其API 组资源类型命名空间(用于命名空间作用域的资源)和名称来区分。 API服务器透明地处理API版本之间的转换:所有不同的版本实际上都是相同持久化数据的呈现API服务器可以通过多个API版本提供相同的底层数据。

例如,假设针对相同的资源有两个API版本:v1v1beta1。 如果你最初使用其APIv1beta1版本创建了一个对象, 你稍后可以使用v1beta1v1 API版本来读取、更新或删除该对象, 直到v1beta1版本被废弃和移除为止。此后,你可以使用v1 API继续访问和修改该对象。

API 变更
任何成功的系统都要随着新的使用案例的出现和现有案例的变化来成长和变化。 为此,Kubernetes已设计了Kubernetes API来持续变更和成长。Kubernetes项目的目标是 不要 给现有客户端带来兼容性问题,并在一定的时期内维持这种兼容性, 以便其他项目有机会作出适应性变更。

一般而言,新的API资源和新的资源字段可以被频繁地添加进来。 删除资源或者字段则要遵从API废弃策略。

Kubernetes对维护达到正式发布(GA)阶段的官方API的兼容性有着很强的承诺,通常这一API版本为v1。 此外,Kubernetes保持与 Kubernetes官方APIBeta API版本持久化数据的兼容性, 并确保在该功能特性已进入稳定期时数据可以通过GA API版本进行转换和访问。

如果你采用一个Beta API版本,一旦该API进阶,你将需要转换到后续的Beta或稳定的API版本。 执行此操作的最佳时间是 Beta API 处于弃用期,因为此时可以通过两个API版本同时访问那些对象。 一旦Beta API结束其弃用期并且不再提供服务,则必须使用替换的API版本。

说明
尽管Kubernetes也努力为Alpha API版本维护兼容性,在有些场合兼容性是无法做到的。 如果你使用了任何Alpha API版本,需要在升级集群时查看Kubernetes发布说明, 如果API确实以不兼容的方式发生变更,则需要在升级之前删除所有现有的Alpha对象。

4.6.5 API 扩展

有两种途径来扩展 Kubernetes API

  1. 你可以使用自定义资源来以声明式方式定义API服务器如何提供你所选择的资源 API。
  2. 你也可以选择实现自己的聚合层来扩展Kubernetes API

※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※

你可能感兴趣的:(面试,docker)