探索Docker:原理、安装与基础应用

进程:

一旦“程序”被执行起来,它就从磁盘上的二进制文件,变成了计算机内存中的数据、寄存器里的值、堆栈中的指令、被打开的文件,以及各种设备的状态信息的一个集合。像这样一个程序运行起来后的计算机执行环境的总和称为进程

静态表现:存储在磁盘中的代码

动态表现:运行时计算机数据和状态的总和

容器的核心技术:通过约束和修改进程的动态表现,从而创造一个边界

涉及到的系统调用:

  • clone() – 实现线程的系统调用,用来创建一个新的进程,并可以通过设计上述参数达到隔离。
  • unshare() – 使某进程脱离某个namespace
  • setns() – 把某进程加入到某个namespace

一 修改进程视图:namespace

namespace类型:

  • PID Namespace
  • Mount Namespace
  • UTS Namespace
  • IPC Namespace
  • Network Namespace
  • User Namespace

原理:在创建容器进程时,指定了这个进程所需要启用的一组 Namespace 参数。这样,容器就只能“看”到当前 Namespace 所限定的资源、文件、设备、状态,或者配置。而对于宿主机以及其他不相关的程序,它就完全看不到了。

二 约束:Cgroup

Linux Cgroups 的全称是 Linux Control Group。它最主要的作用,就是限制一个进程组能够使用的资源上限,包括 CPU、内存、磁盘、网络带宽等等。此外,Cgroups 还能够对进程进行优先级设置、审计,以及将进程挂起和恢复等操作

操作

#比如控制cpu
cd /sys/fs/cgroup/cpu
#创建一个控制组,也就是一个目录,会自动生成可以控制的配置文件
mkdir container
#比如可以用来限制进程在长度为 cfs_period 的一段时间内,只能被分配到总量为 cfs_quota 的 CPU 时间。
echo 20000 > /sys/fs/cgroup/cpu/container/cfs_quota_us
#20000 代表20ms,cpu.cfs_period_us一般是100ms,表示100ms内,被该控制组限制的进程只能使用 20 ms 的 CPU 时间
echo 被控制进程的pid > /sys/fs/cgroup/cpu/container/tasks

Linux Cgroups 的设计还是比较易用的,简单粗暴地理解呢,它就是一个子系统目录加上一组资源限制文件的组合。而对于 Docker 等 Linux 容器项目来说,它们只需要在每个子系统下面,为每个容器创建一个控制组(即创建一个新目录),然后在启动容器进程之后,把这个进程的 PID 填写到对应控制组的 tasks 文件中就可以了。

注意: Mount Namespace 跟其他 Namespace 的使用略有不同的地方:它对容器进程视图的改变,一定是伴随着挂载操作(mount)才能生效。

三 rootfs 根文件系统

切换进程的根目录(Change Root)。

  • 拷贝必要的文件
  • pivot_root 系统调用,如果系统不支持,使用 chroot。

需要明确的是,rootfs 只是一个操作系统所包含的文件、配置和目录,并不包括操作系统内核。在 Linux 操作系统中,这两部分是分开存放的,操作系统只有在开机启动时才会加载指定版本的内核镜像。

同一台机器上的所有容器,都共享宿主机操作系统的内核。

docker安装

  1. 更新软件包索引:首先,使用以下命令更新系统的软件包索引:
    sudo yum check-update
  2. 安装需要的软件:安装一些必要的软件包,以便使用 Docker 的软件源:
    sudo yum install -y yum-utils device-mapper-persistent-data lvm2
  3. 设置 Docker 软件源:使用以下命令设置 Docker CE 软件源:
    sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
  4. 安装 Docker CE:现在,可以使用以下命令安装 Docker CE:
    sudo yum install docker-ce
  5. 启动 Docker 服务:安装完成后,可以启动 Docker 服务并设置开机自启:
    sudo systemctl start docker
    sudo systemctl enable docker
  6. 验证 Docker 安装:最后,您可以运行以下命令来验证 Docker 是否成功安装:
    sudo docker run hello-world

    如果 Docker 安装正确,将会输出 “Hello from Docker!” 的信息。

  7. 配置用户权限(可选):如果您希望无需使用 sudo 来运行 Docker 命令,可以将当前用户添加到 Docker 用户组中。首先,执行以下命令将当前用户添加到 Docker 用户组:
    sudo usermod -aG docker $USER

docker镜像的结构

  • 只读层:最基础的文件
  • init层:可动态配置读写,但是不能commit的层
  • 读写层:增量修改可以commit和push的层

Dockerfile

# 使用官方提供的Python开发镜像作为基础镜像
FROM python:2.7-slim

# 将工作目录切换为/app
WORKDIR /app

# 将当前目录下的所有内容复制到/app下
ADD . /app

# 使用pip命令安装这个应用所需要的依赖
RUN pip install --trusted-host pypi.python.org -r requirements.txt

# 允许外界访问容器的80端口
EXPOSE 80

# 设置环境变量
ENV NAME World

# 设置容器进程为:python app.py,即:这个Python应用的启动命令
CMD ["python", "app.py"]

默认情况下,Docker 会提供一个隐含的 ENTRYPOINT,即:/bin/sh -c。所以,在不指定 ENTRYPOINT 时,比如这个例子里,实际上运行在容器里的完整进程是:/bin/sh -c "python app.py",即 CMD 的内容就是 ENTRYPOINT 的参数

注意:Dockerfile 中的每个原语执行后,都会生成一个对应的镜像层。即使原语本身并没有明显地修改文件的操作(比如,ENV 原语),它对应的层也会存在。只不过在外界看来,这个层是空的。

可以使用 docker commit 指令,把一个正在运行的容器,直接提交为一个镜像

docker常用命令:


#镜像相关命令:
docker images:列出本地主机上的镜像列表。
docker pull <image_name>:从 Docker 镜像仓库下载镜像。
docker build -t <image_name> <dir_path>:根据 Dockerfile 构建镜像。
docker push <image_name>:将本地镜像推送到镜像仓库。
#容器相关命令:
docker ps:列出正在运行的容器。
docker ps -a:列出所有容器,包括已停止的容器。
docker run <image_name>:根据镜像创建并启动一个容器。
docker stop <container_id>:停止一个运行中的容器。
docker rm <container_id>:删除一个已停止的容器。
#日志和进入容器命令:
docker logs <container_id>:查看容器的日志。
docker exec -it <container_id> <command>:在运行中的容器中执行命令,并进入容器的 shell 终端。
#网络相关命令:
docker network ls:列出 Docker 网络。
docker network create <network_name>:创建一个自定义网络。
docker network connect <network_name> <container_name>:将容器连接到指定网络。
#数据卷相关命令:
docker volume ls:列出 Docker 数据卷。
docker volume create <volume_name>:创建一个数据卷。
docker volume inspect <volume_name>:查看数据卷的详细信息。
docker volume rm <volume_name>:删除一个数据卷。
#查看docker容器运行的进程号
docker inspect --format '{{ .State.Pid }}'  4ddf4638572d
25686

docker exec 是怎么做到进入容器里的?

每个进程的每种 Linux Namespace,都在它对应的 /proc/[进程号]/ns 下有一个对应的虚拟文件,并且链接到一个真实的 Namespace 文件上。

setns() 的 Linux 系统调用

#define _GNU_SOURCE
#include <fcntl.h>
#include <sched.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE);} while (0)

int main(int argc, char *argv[]) {
    int fd;
    
    fd = open(argv[1], O_RDONLY);
    if (setns(fd, 0) == -1) {
        errExit("setns");
    }
    execvp(argv[2], &argv[2]); 
    errExit("execvp");
}
  • argv[1],即当前进程要加入的 Namespace 文件的路径/proc/25686/ns/net
  • argv[2]则是你要在这个 Namespace 里运行的进程 /bin/bash。

open() 系统调用打开了指定的 Namespace 文件,并把这个文件的描述符 fd 交给 setns() 使用。在 setns() 执行后,当前进程就加入了这个文件对应的 Linux Namespace 当中了。

数据卷Volumn

$ docker run -v /test ... 
$ docker run -v /home:/test ...
  • 命令1:由于你并没有显示声明宿主机目录,那么 Docker 就会默认在宿主机上创建一个临时目录 /var/lib/docker/volumes/[VOLUME_ID]/_data,然后把它挂载到容器的 /test 目录上。
  • 命令2,Docker 就直接把宿主机的 /home 目录挂载到容器的 /test 目录上。

原理:在 rootfs 准备好之后,在执行 chroot 之前,把 Volume 指定的宿主机目录(比如 /home 目录),挂载到指定的容器目录(比如 /test 目录)在宿主机上对应的目录(即 /var/lib/docker/aufs/mnt/[可读写层 ID]/test)上,这个 Volume 的挂载工作就完成了。

由于执行这个挂载操作时,“容器进程”已经创建了,也就意味着此时 Mount Namespace 已经开启了。所以,这个挂载事件只在这个容器里可见。你在宿主机上,是看不见容器内部的这个挂载点的。这就保证了容器的隔离性不会被 Volume 打破。

注意:这里提到的"容器进程",是 Docker 创建的一个容器初始化进程 (dockerinit),而不是应用进程 (ENTRYPOINT + CMD)。dockerinit 会负责完成根目录的准备、挂载设备和目录、配置 hostname 等一系列需要在容器内进行的初始化操作。最后,它通过 execv() 系统调用,让应用进程取代自己,成为容器里的 PID=1 的进程。

另外,由于容器的镜像操作,比如 docker commit,都是发生在宿主机空间的。而由于 Mount Namespace 的隔离作用,宿主机并不知道这个绑定挂载的存在。所以,在宿主机看来,容器中可读写层的 /test 目录(/var/lib/docker/aufs/mnt/[可读写层 ID]/test),始终是空的。所以虽然这个 /test 目录里的内容,挂载在容器 rootfs 的可读写层,但是不会被 docker commit 提交

Linux 的绑定挂载(bind mount)机制。它的主要作用就是,允许你将一个目录或者文件,而不是整个设备,挂载到一个指定的目录上。并且,这时你在该挂载点上进行的任何操作,只是发生在被挂载的目录或者文件上,而原挂载点的内容则会被隐藏起来且不受影响。

容器和虚拟机的对比

  • 虚拟机实现了更深层次的资源隔离,而docker还是依赖宿主机操作系统的隔离性,多个容器共享的是同一个宿主机的操作系统内核。不能跨操作系统运行docker容器。另外还有很多对象是不能被namespace化的,比如时间
  • 虚拟机必须要创建一个完整的操作系统,带来额外的资源消耗与占用,docker更加轻量级(敏捷,高性能)

扩展博客:Docker基础技术:Linux Namespace(上) | 酷 壳 - CoolShell

遗留问题:

1 容器和应用共生死,生命周期

2 /proc文件系统,不了解cgroup的限制,在容器里读取到的 CPU 核数、可用内存等信息都是宿主机上的数据

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/462495.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数据结构:基于数组实现简单的数据缓存区(简单队列)

1 前言 在我们使用CAN或者以太网调试时&#xff0c;经常需要缓存最近n次收到的数据&#xff0c;以便于我们对数据进行分析。 实现这一想法我们很容易就会想到队列&#xff0c;队列就是一种先进先出的数据结构&#xff0c;之前在《数据结构&#xff1a;基于数组的环形队列&…

win10 + cpu + pycharm + mindspore

MindSpore是华为公司自研的最佳匹配昇腾AI处理器算力的全场景深度学习框架。 1、打开官网&#xff1a; MindSpore官网 2、选择以下选项&#xff1a; 3、创建conda 环境&#xff0c;这里python 选择3.9.0&#xff0c;也可以选择其他版本&#xff1a; conda create -c conda-…

xray问题排查,curl: (35) Encountered end of file(已解决)

经过了好几次排查&#xff0c;都没找到问题&#xff0c;先说问题的排查过程&#xff0c;多次确认了user信息&#xff0c;包括用户id和alterid&#xff0c;都没问题&#xff0c;头大的一逼 问题排查过程 确保本地的xray服务是正常的 [rootk8s-master01 xray]# systemctl stat…

【力扣白嫖日记】1934.确认率

前言 练习sql语句&#xff0c;所有题目来自于力扣&#xff08;https://leetcode.cn/problemset/database/&#xff09;的免费数据库练习题。 今日题目&#xff1a; 1934.确认率 表&#xff1a;Signups 列名类型user_idinttime_stampdatetime User_id是该表的主键。每一行都…

人工智能原理:探索智能的奥秘

人工智能&#xff08;Artificial Intelligence&#xff09;&#xff0c;英文缩写为AI。是新一轮科技革命和产业变革的重要驱动力量&#xff0c;是研究、开发用于模拟、延伸和扩展人的智能的理论、方法、技术及应用系统的一门新的技术科学。 人工智能是智能学科重要的组成部分&a…

XXE漏洞原理和pikachu靶场实验

★★免责声明★★ 文章中涉及的程序(方法)可能带有攻击性&#xff0c;仅供安全研究与学习之用&#xff0c;读者将信息做其他用途&#xff0c;由Ta承担全部法律及连带责任&#xff0c;文章作者不承担任何法律及连带责任。 1、XXE漏洞原理 XXE全称&#xff1a;XML External Enti…

YOLOv9更换iou|包含CIoU、DIoU、MDPIoU、GIoU

专栏介绍&#xff1a;YOLOv9改进系列 | 包含深度学习最新创新&#xff0c;助力高效涨点&#xff01;&#xff01;&#xff01; 一、改进点介绍 更换YOLOv9中使用的Iou计算方式&#xff0c;目前支持CIoU、DIoU、MDPIoU、GIoU。 二、Iou模块详解 2.1 模块简介 Iou的主要思想&…

【Poi-tl Documentation】自定义行删除标签

前置说明&#xff1a; <dependency><groupId>com.deepoove</groupId><artifactId>poi-tl</artifactId><version>1.12.1</version> </dependency>模板样式&#xff1a; 删除行表格测试.docx 实现思路&#xff1a;通过定制占位…

ctfshow(WEB AK赛)

目录 web-观己 web1-观字 web2-观星 web3-观图 web4-观心 过程and分析 web-观己 没啥难的有include 想着伪协议 但是过滤了php 那就是用file为协议读取本地文件 全靠猜 <?php if(isset($_GET[file])){$file $_GET[file];if(preg_match(/php/i, $file)){die(error);}…

win下 VirtualBox 自动启动脚本脚本

文章目录 一、找到VBoxManage二、测试脚本1、打开cmd2、输入命令 (直接把上面找到的VBoxManage.exe 拖入到cmd中&#xff0c;这样就不用输入路径了)3、效果展示 比如虚拟机中的系统名称叫“centos-mini” 三、设置自动启动脚本1、复制刚才测试好的命令到新建文本中2、修改文本名…

SpringBoot整合Seata注册到Nacos服务

项目引入pom文件 <!-- SpringCloud Seata 组件--> <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-seata</artifactId><version>${alibaba.seata}</version><exclusions><exc…

Vintage账龄分析表计算底层逻辑(Python实操)

大家好&#xff0c;我是东哥。 信贷风控领域中&#xff0c;经常用到账龄Vintage报表&#xff0c;这是入门初学者的难点之一&#xff0c;因为它涉及到用户还款、逾期等多种行为以及业务上的多种统计口径&#xff0c;因此很多朋友一直无法将逻辑梳理清楚。本次来给大家详细介绍V…

计算机系统基础 2 Intel 中央处理器

Intel微处理器的发展史 INTegrated ELectronics&#xff08;集成电子&#xff09;的缩写 先后推出的中央处理器&#xff1a; Intel4004、Intel8008、Intel8080/8085、8086/8088、80186、80286、i386、i486 Pentium&#xff08;奔腾&#xff09;、Pentium II、Pentium III、Pen…

布局Uniswap(UNI)的基本逻辑和bitget钱包使用教程

我们都知道&#xff0c;牛市里板块轮动是很明显的&#xff0c;这个概念涨完下一个概念涨&#xff01; 背后本质是场内的筹码在交换的过程&#xff0c;抓住这种交换的规律&#xff0c;可以大大提高资金的使用效率和总体收益&#xff01; 目前行情继续稳中有进&#xff0c;大饼也…

html--花瓣

代码 <!DOCTYPE html> <html lang"en" ><head> <meta charset"UTF-8"> <title>Petals</title><link rel"stylesheet" href"css/style.css"></head><body><div class"…

记录工作中莫名其妙的bug

1、问题&#xff1a;办公室的电脑突然除了我之外&#xff0c;都不能访问我们的线上系统了 原因&#xff1a;因为是内网&#xff0c;同事有刚刚升级了Windows11&#xff0c;配置的DNS被清了&#xff0c;还有同事换了公司的新电脑&#xff0c;还没有配DNS 位于&#xff1a;C /Win…

postman---postman参数化

我们在做接口测试的过程中&#xff0c;都会遇到同一个接口不同的数据&#xff0c;每次去一个个填写数据就太麻烦了&#xff0c;今天我们一起学习下如何通过postman进行参数化 一、参数化 参数化就是1个接口请求不同的数据&#xff0c;我们可以通过把请求的数据放入到一个文件…

创业板指399006行情数据API接口

# 测试&#xff1a;返回不超过10条数据&#xff08;2年历史&#xff09; https://tsanghi.com/api/fin/index/CHN/daily?tokendemo&ticker399006&order2Python示例 import requestsurl f"https://tsanghi.com/api/fin/index/CHN/daily?tokendemo&ticker399…

某团mtgsig1.1和_token逆向

前言 只作学习研究&#xff0c;禁止用于非法用途&#xff0c;否则后果自负&#xff0c;如有侵权&#xff0c;请告知删除&#xff0c;谢谢&#xff01; 目前已成功逆向&#xff01;&#xff01; 1.1版本适用于h5和小程序 使用python调用js逆向脚本&#xff0c;获取mtgsig 效…

【Python使用】python高级进阶知识md总结第4篇:静态Web服务器-命令行启动动态绑定端口号,html 的介绍【附代码文档】

python高级进阶全知识知识笔记总结完整教程&#xff08;附代码资料&#xff09;主要内容讲述&#xff1a;操作系统&#xff0c;虚拟机软件&#xff0c;Ubuntu操作系统&#xff0c;Linux内核及发行版&#xff0c;查看目录命令&#xff0c;切换目录命令&#xff0c;绝对路径和相对…