如何做好容器化管理?腾讯架构师一篇文章带你吃透 Docker 原理

云安全SRC漏洞挖掘实战:从攻击面梳理到漏洞报告全流程 在云计算时代,身份与访问管理(IAM)和资源配置安全成为核心议题。其原理在于,云环境通过API驱动服务,任何不当的配置或权限设置都可能破坏预设的安全边界。理解这一机制的技术价值在于,能够系统性地识别从计算、存储到容器编排等层面的攻击面,从而有效防御数据泄露与权限滥用风险。在应用场景上,无论是对象存储桶的错误配置,还是云服务器元数据服务的滥用,都要求安全从业者具备立体化的渗透测试思维。本文聚焦于云安全应急响应中心(SRC)的漏洞挖掘,详细拆解了包括容器逃逸和IAM策略绕过在内的实战场景,为安全研究者提供了一套 阅读详情

本文已收录GitHub,更有互联网大厂面试真题,面试攻略,高效学习资料等

一、容器的实现原理

从本质上,容器其实就是一种沙盒技术。就好像把应用隔离在一个盒子内,使其运行。因为有了盒子边界的存在,应用于应用之间不会相互干扰。并且像集装箱一样,拿来就走,随处运行。其实这就是 PaaS 的理想状态。

实现容器的核心,就是要生成限制应用运行时的边界。我们知道,编译后的可执行代码加上数据,叫做程序。而把程序运行起来后,就变成了进程,也就是所谓的应用。如果能在应用启动时,给其加上一个边界,这样不就能实现期待的沙盒吗?

在 Linux 中,实现容器的边界,主要有两种技术 Cgroups 和 Namespace. Cgroups 用于对运行的容器进行资源的限制,Namespace 则会将容器隔离起来,实现边界。

这样看来,容器只是一种被限制的了特殊进程而已。

二、容器的隔离:Namespace

在介绍 Namespace 前,先看一个实验:

# 使用 python3.6.8 的官方镜像,建立了一个运行 django 的环境
# 进入该容器后,使用 ps 命令,查看运行的进程
root@8729260f784a:/src# ps -A
  PID TTY          TIME CMD
    1 ?        00:01:22 gunicorn
   22 ?        00:01:20 gunicorn
   23 ?        00:01:24 gunicorn
   25 ?        00:01:30 gunicorn
   27 ?        00:01:16 gunicorn
   41 pts/0    00:00:00 bash
   55 pts/0    00:00:00 ps

可以看到,容器内 PID =1 的进程,是 gunicorn 启动的 django 应用。熟悉 Linux 的同学都知道,PID =1 的进程是系统启动时的第一个进程,也称 init 进程。其他的进程,都是由它管理产生的。而此时,PID=1 确实是 django 进程。

接着,退出容器,在宿主机执行 ps 命令

# 环境为 Centos7
[root@localhost ~]# ps -ef | grep gunicorn
root      9623  8409  0 21:29 pts/0    00:00:00 grep --color=auto gunicorn
root     30828 30804  0 May28 ?        00:01:22 /usr/local/bin/python /usr/local/bin/gunicorn -c gunicorn_config.py ctg.wsgi
root     31171 30828  0 May28 ?        00:01:20 /usr/local/bin/python /usr/local/bin/gunicorn -c gunicorn_config.py ctg.wsgi
root     31172 30828  0 May28 ?        00:01:24 /usr/local/bin/python /usr/local/bin/gunicorn -c gunicorn_config.py ctg.wsgi
root     31174 30828  0 May28 ?        00:01:30 /usr/local/bin/python /usr/local/bin/gunicorn -c gunicorn_config.py ctg.wsgi
root     31176 30828  0 May28 ?        00:01:16 /usr/local/bin/python /usr/local/bin/gunicorn -c gunicorn_config.py ctg.wsgi

如果以宿主机的视角,发现 django 进程 PID 变成了 30828. 这也就不难证明,在容器中,确实做了一些处理。把明明是 30828 的进程,变成了容器内的第一号进程,同时在容器还看不到宿主机的其他进程。这也说明容器内的环境确实是被隔离了。

这种处理,其实就是 Linux 的 Namespace 机制。比如,上述将 PID 变成 1 的方法就是通过PID Namespace。在 Linux 中创建线程的方法是 clone, 在其中指定 CLONE_NEWPID 参数,这样新创建的进程,就会看到一个全新的进程空间。而此时这个新的进程,也就变成了 PID=1 的进程。

int pid = clone(main_function, stack_size, CLONE_NEWPID | SIGCHLD, NULL); 

在 Linux 类似于 PID Namespace 的参数还有很多,比如:

三、容器的限制:Cgroups

通过 Namespace 技术,我们实现了容器和容器间,容器与宿主机之间的隔离。但这还不够,想象这样一种场景,宿主机上运行着两个容器。虽然在容器间相互隔离,但以宿主机的视角来看的话,其实两个容器就是两个特殊的进程,而进程之间自然存在着竞争关系,自然就可以将系统的资源吃光。当然,我们不能允许这么做的。

Cgroups 就是 Linux 内核中用来为进程设置资源的一个技术。

Linux Cgroups 全称是 Linux Control Group,主要的作用就是限制进程组使用的资源上限,包括 CPU,内存,磁盘,网络带宽。

还可以对进程进行优先级设置,审计,挂起和恢复等操作。

在之前的版本中,可通过 libcgroup tools 来管理 cgroup, 在 RedHat7 后,已经改为通过 systemctl 来管理。

我们知道,systemd 在 Linux 中的功能就是管理系统的资源。而为了管理的方便,衍生出了一个叫 Unit 的概念,比如一个 unit 可以有比较宽泛的定义,比如可以表示抽象的服务,网络的资源,设备,挂载的文件系统等。为了更好的区分,Linux 将 Unit 的类型主要分为 12 种。

在 Cgroup 中,主要使用的是 slice, scope and service 这三种类型。

如创建一个临时 cgroup, 然后对其启动的进程进行资源限制:

 # 创建一个叫 toptest 的服务,在名为 test 的 slice 中运行
[root@localhost ~]# systemd-run --unit=toptest --slice=test top -b
Running as unit toptest.service.

现在 toptest 的服务已经运行在后台了

# 通过 systemd-cgls 来查看 Cgroup 的信息
[root@localhost ~]#  systemd-cgls
├─1 /usr/lib/systemd/systemd --switched-root --system --deserialize 22
├─test.slice
│ └─toptest.service
│   └─6490 /usr/bin/top -b

# 通过 systemctl status 查看服务的状态
[root@localhost ~]# systemctl status toptest
● toptest.service - /usr/bin/top -b
   Loaded: loaded (/run/systemd/system/toptest.service; static; vendor preset: disabled)
  Drop-In: /run/systemd/system/toptest.service.d
           └─50-Description.conf, 50-ExecStart.conf, 50-Slice.conf
   Active: active (running) since Tue 2020-06-02 14:01:01 CST; 3min 50s ago
 Main PID: 6490 (top)
   CGroup: /test.slice/toptest.service
           └─6490 /usr/bin/top -b

现在对运行的 toptest 服务进行资源的限制。

# 先看下,没有被限制前的 Cgroup 的信息, 6490 为进程 PID
[root@localhost ~]# cat /proc/6490/cgroup
11:pids:/test.slice
10:blkio:/test.slice
9:hugetlb:/
8:cpuset:/
7:memory:/test.slice
6:devices:/test.slice
5:net_prio,net_cls:/
4:perf_event:/
3:freezer:/
2:cpuacct,cpu:/test.slice
1:name=systemd:/test.slice/toptest.service

# 对其使用的 CPU 和 内存进行限制
systemctl set-property toptest.service CPUShares=600 MemoryLimit=500M

# 再次查看 Cgroup 的信息,发现在 cpu 和 memory 追加了一些内容。
[root@localhost ~]# cat /proc/6490/cgroup
11:pids:/test.slice
10:blkio:/test.slice
9:hugetlb:/
8:cpuset:/
7:memory:/test.slice/toptest.service
6:devices:/test.slice
5:net_prio,net_cls:/
4:perf_event:/
3:freezer:/
2:cpuacct,cpu:/test.slice/toptest.service
1:name=systemd:/test.slice/toptest.service

这时可以在 /sys/fs/cgroup/memory/test.slice 和 /sys/fs/cgroup/cpu/test.slice 目录下,多出了一个叫 toptest.service 的目录。

在其目录下 cat toptest.service/cpu.shares 可以发现,里面的 CPU 被限制了 600.

回到 Docker,其实 docker 和我们上面做的操作基本一致,具体需要限制哪些资源就是在 docker run 里指定:

$ docker run -it --cpu-period=100000 --cpu-quota=20000 ubuntu /bin/bash

关于 docker 具体的限制,可以在 sys/fs/cgroup/cpu/docekr/ 等文件夹来查看。

四、容器的文件系统:容器镜像 - rootfs

现在我们知道,容器技术的核心就是通过 Namespace 限制了容器看到的视野,通过 Cgroup限制了容器可访问的资源。 但关于 Mount Namespace 还有一些特殊的地方,需要着重关注下。

Mount Namespace 特殊之处在于,除了在修改时需要进程对文件系统挂载点的认证,还需要显式声明需要挂载那些目录。在 Linux 系统中,有一个叫 chroot 的命令,可以改变进程的根目录到指定的位置。而 Mount Namespace 正是基于 chroot 的基础上发展出来的。

在容器内,应该看到完全独立的文件系统,而且不会受到宿主机以及其他容器的影响。这个独立的文件系统,就叫做容器镜像。它还有一个更专业的名字叫 rootfs. rootfs 中包含了一个操作系统所需要的文件,配置和目录,但并不包含系统内核。 因为在 Linux 中,文件和内核是分开存放的,操作系统只有在开启启动时才会加载指定的内核。这也就意味着,所有的容器都会共享宿主机上操作系统的内核。

在 PaaS 时代,由于云端和本地的环境不同,应用打包的过程,一直是比较痛苦的过程。但有了 rootfs ,这个问题就被很好的解决了。因为在镜像内,打包的不仅仅是应用,还有所需要的依赖,都被封装在一起。这就解决了无论是在哪,应用都可以很好的运行的原因。

不光这样,rootfs 还解决了可重用性的问题,想象这个场景,你通过 rootfs 打包了一个包含 java 环境的 centos 镜像,别人需要在容器内跑一个 apache 的服务,那么他是否需要从头开始搭建 java 环境呢?docker 在解决这个问题时,引入了一个叫层的概念,每次针对 rootfs 的修改,都只保存增量的内容,而不是 fork 一个新镜像。

层级的想法,同样来自于 Linux,一个叫 union file system (联合文件系统)。它最主要的功能就是将不同位置的目录联合挂载到同一个目录下。对应在 Docker 里面,不同的环境则使用了不同的联合文件系统。比如 centos7 下最新的版本使用的是 overlay2,而 Ubuntu 16.04 和 Docker CE 18.05 使用的是 AuFS.

可以通过 docker info 来查询使用的存储驱动,我这里的是 overlay2。

[root@localhost ~]# docker info
Client:
 Debug Mode: false

Server:
 Containers: 4
  Running: 4
  Paused: 0
  Stopped: 0
 Images: 4
 Server Version: 19.03.8
 Storage Driver: overlay2

接着我们来了解下,Overlay2 的文件系统在 docker 中是如何使用的?

Overlay2

在 Linux 的主机上,OverlayFS 一般有两个目录,但在显示时具体会显示为一个目录。这两个目录被称为层,联合在一起的过程称为 union mount. 在其下层的目录称为 lowerdir, 上层的目录称为 upperdir. 两者联合后,暴露出来的视图称为 view. 听起来有点抽象,先看下整体结构:

可以看到,lowerdir 其实对应的就是镜像层,upperdir 对应的就是容器器。而 merged 对应的就是两者联合挂载之后的内容。而且我们发现,当镜像层和容器层拥有相同的文件时,会以容器层的文件为准(最上层的文件为准)。通常来说,overlay2 支持最多 128 lower 层。

下面实际看下容器层和镜像具体的体现,我这台 linux 主机上,运行着 4 个 container。

Docker 一般的存储位置在 /var/lib/docker,先看下里面的结构:

[root@localhost docker]# ls -l /var/lib/docker
total 16
drwx------.  2 root root   24 Mar  4 03:39 builder
drwx--x--x.  4 root root   92 Mar  4 03:39 buildkit
drwx------.  7 root root 4096 Jun  1 10:36 containers
drwx------.  3 root root   22 Mar  4 03:39 image
drwxr-x---.  3 root root   19 Mar  4 03:39 network
drwx------. 69 root root 8192 Jun  1 15:01 overlay2
drwx------.  4 root root   32 Mar  4 03:39 plugins
drwx------.  2 root root    6 Jun  1 15:00 runtimes
drwx------.  2 root root    6 Mar  4 03:39 swarm
drwx------.  2 root root    6 Jun  1 15:01 tmp
drwx------.  2 root root    6 Mar  4 03:39 trust
drwx------.  3 root root   45 May 18 10:28 volumes

需要着重关注的是 container, image, overlay2 这几个文件夹。

  • container:这个不用多说,正在运行或创建的容器会在这个目录下。
  • image:对应记录的就是镜像。
  • overlay2:记录的是每个镜像下包含的 lowerrdir.

之前提到,unionfs 的实现可能有多种,比如 overlay2,aufs,devicemapper 等。那么自然在 image 文件夹下,就会存在多种驱动的文件夹,:

image/
└── overlay2
    ├── distribution
    ├── imagedb
    │   ├── content
    │   └── metadata
    ├── layerdb
    │   ├── mounts
    │   ├── sha256
    │   └── tmp
    └── repositories.json

这里的 imagedb 和 layerdb, 就是存储元数据的地方。之前我们了解到,容器的文件系统构成就是通过 image 层 和 container 层联合构成的,而每个 image 可能是由多个层构成。这就意味着,每个层可能会被多个 image 引用。那么之间是如何关联的呢?答案就在 imagedb 这个文件下。

这里我以 mysql 镜像为例:

# 查看 mysql 的镜像 id
[root@localhost docker]# docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ctg/mysql           5.7.29              84164b03fa2e        3 months ago        456MB

# 进入到 imagedb/content/sha256 目录, 可以找到对应的镜像 id
[root@localhost docker]# ls -l image/overlay2/imagedb/content/sha256/
...
-rw-------. 1 root root  6995 Apr 27 02:45 84164b03fa2ecb33e8b4c1f2636ec3286e90786819faa4d1c103ae147824196a

# 接着看下里面记录的内容, 这里截取有用的部分
cat  image/overlay2/imagedb/content/sha256/84164b03fa2ecb33e8b4c1f2636ec3286e90786819faa4d1c103ae147824196a
{
.........
  "os": "linux",
  "rootfs": {
    "type": "layers",
    "diff_ids": [
      "sha256:f2cb0ecef392f2a630fa1205b874ab2e2aedf96de04d0b8838e4e728e28142da",
      "sha256:a9f6b7c7101b86ffaa53dc29638e577dabf5b24150577a59199d8554d7ce2921",
      "sha256:0c615b40cc37ed667e9cbaf33b726fe986d23e5b2588b7acbd9288c92b8716b6",
      "sha256:ad160f341db9317284bba805a3fe9112d868b272041933552df5ea14647ec54a",
      "sha256:1ea6ef84dc3af6506c26753e9e2cf7c0d6c1c743102b85ebd3ee5e357d7e9bc4",
      "sha256:6fce4d95d4af3777f3e3452e5d17612b7396a36bf0cb588ba2ae1b71d139bab9",
      "sha256:6de3946ea0137e75dcc43a3a081d10dda2fec0d065627a03800a99e4abe2ede4",
      "sha256:a35a4bacba4d5402b85ee6e898b95cc71462bc071078941cbe8c77a6ce2fca62",
      "sha256:1ff9500bdff4455fa89a808685622b64790c321da101d27c17b710f7be2e0e7e",
      "sha256:1cf663d0cb7a52a3a33a7c84ff5290b80966921ee8d3cb11592da332b4a9e016",
      "sha256:bcb387cbc5bcbc8b5c33fbfadbce4287522719db43d3e3a286da74492b7d6eca"
    ]
  }
}

可以看到 mysql 镜像由 11 层组成,其中 f2cb 是最低层,bcb3 是最上层。

接着,我们看下 layerdb 的内容:

[root@localhost docker]# ls -l  image/overlay2/layerdb/
total 8
drwxr-xr-x.  6 root root 4096 May 13 13:38 mounts
drwxr-xr-x. 39 root root 4096 Apr 27 02:51 sha256
drwxr-xr-x.  2 root root    6 Apr 27 02:51 tmp

# 首先看下 sha256 目录下的内容
[root@localhost docker]# ls -l  image/overlay2/layerdb/sha256/
total 0
....
drwx------. 2 root root 71 Apr 27 02:45 bbb9cccab59a16cb6da78f8879e9d07a19e3a8d49010ab9c98a2c348fa116c87
drwx------. 2 root root 71 Apr 27 02:45 f2cb0ecef392f2a630fa1205b874ab2e2aedf96de04d0b8838e4e728e28142da
....

可以发现,在这里仅能找到最底层的层 ID,原因在于层之间的关联是通过 chainID 的方式保存的,简单来说就是通过 sha256 算法后能计算出一层的容器 id.

比如这里,最底层 id 是 f2cb0ecef392f2a630fa1205b874ab2e2aedf96de04d0b8838e4e728e28142da , 上一层 id 是 a9f6b7c7101b86ffaa53dc29638e577dabf5b24150577a59199d8554d7ce2921, 那么对应在 sha256 目录下的下一层 id 的计算方法就是:

[root@localhost docker]# echo -n "sha256:f2cb0ecef392f2a630fa1205b874ab2e2aedf96de04d0b8838e4e728e28142da sha256:a9f6b7c7101b86ffaa53dc29638e577dabf5b24150577a59199d8554d7ce2921" | sha256sum
bbb9cccab59a16cb6da78f8879e9d07a19e3a8d49010ab9c98a2c348fa116c87  -

接着我们可以在 sha256 目录下,找到 bbb9… 这层的内容。

OK,现在我们已经把镜像和层关联起来,但之前说过,image 目录下存的都是元数据。真实的 rootfs 其实在另一个地方 - /docker/overlay2 下。

# 通过查询 cache-id,得到就是真实的 rootfs 层
[root@localhost docker]# cat  image/overlay2/layerdb/sha256/f2cb0ecef392f2a630fa1205b874ab2e2aedf96de04d0b8838e4e728e28142da/cache-id
2996b24990e75cbd304093139e665a45d96df8d7e49334527827dcff820dbf16[

进入到 /docker/overlay2 下查看:

[root@localhost docker]# ls -l overlay2/
total 4
...
drwx------. 3 root root   47 Apr 27 02:45 2996b24990e75cbd304093139e665a45d96df8d7e49334527827dcff820dbf16
...
drwx------. 2 root root 4096 May 13 13:38 l

这样真实的 rootfs 层也被找到了。

这里重新梳理下,我们先是在 mage/overlay2/imagedb/content/sha256/ ,根据 image id 查看该 image 具有所有的层ID,然后根据最底层ID和上层ID通过 sha256 计算得到,引用的上一层 ID, 依次类推,关联所有的层。最后通过每一层的 cache-id,将元数据和真实的 rootfs 层数据对应起来了。

最后总结一下,rootfs 的构成。

每个 rootfs 由镜像层(lowerdir)和 容器层(upperdir)构成,其中镜像层只能只读,而容器层则能读写。而且镜像层可有最多128层构成。

其实,rootfs 构成还有另外一层,但由于在进行提交或编译时,不会把这层加进去,所以就没把这层算在rootfs里面,但实际上存在的。

在之前我们查看 ls -l /var/lib/docker/overlay2/ 下镜像层,会看到好几个以 -init 结尾的目录,而且数量恰好等于容器的数量。这层夹在镜像层之上,容器层之下。是由 docker 内部单独生成的一层,专门用于存放 etc/hosts、/etc/resolv.conf 等配置信息。存在的目的,是由于用户在容器启动时,需要配置一些特定的值,比如 hostname,dns 等,但这些配置仅对当前容器有效,放到其他环境下自然有别的配置,所以这层被单独拿出来,在提交镜像时,忽略这一层。

五、容器与虚拟机技术的对比

下面这张图是 docker 官方中,截取下来的,基于上面我们学习的内容,重新分析下 docker 和 传统 VM 的区别:

迁移性和性能:

  • 传统 VM: 需要基于 Hypervisor 的硬件虚拟化技术,模拟出 CPU,内存等硬件。然后在其上搭建一套完整的操作系统,自然在性能上会有很大的损失。迁移自然更不用说,传统的 ova 导出后就是一个完整的操作系统。
  • Docker:Docker 将 Hypervisor 的位置换成自己的 Docekr Engine. 然后运行的容器仅仅是一个特殊的进程,自然性能不会有太大的损失。并且可以应用和其所需要的系统文件打包成镜像,无论在哪读可以正常运行,而且相对于 ova 来说体积也小了更多。(需要内核支持)

一般来说,运行着 CentOS 的 KVM,启动后,在不做优化的前提下,需要占用 100~200 M 内存。在加上用户对宿主机的调用,需要通过虚拟化软件拦截和处理,又是一层性能损耗,特别是对计算资源,网络和磁盘I/O等。

隔离性:

  • 传统 VM:由于是虚拟化出一套完整的操作系统,所以隔离性非常好。比如微软的 Azure 平台,就是在 Windows 服务器上,虚拟出大量的 Linux 虚拟机。

  • Docker:在隔离性上相差就很多了,因为本身上容器就是一种进程,而所有的进程都需要共享一个系统内核。

    • 这就意味着,在 Windows 上运行 Linux 容器,或者 Linux 宿主机运行高版本内核的容器就无法实现。
    • 在 Linux 内核中,有许多资源和对象不能 Namespace 化,如时间,比如通过 settimeofday(2) 系统调用 修改时间,整个宿主机的实际都会被修改。
    • 安全的问题,共享宿主机内核的事实,容器暴露出的攻击面更大。

资源的限制:

传统 VM:非常便于管理,控制资源的使用,依赖于虚拟的操作系统。
Docker:由于 docker 内资源的限制通过 Cgroup 实现,而 Cgroup 有很多不完善的地方,比如
对 /proc 的处理问题。进入容器后,执行 top 命令,看到的信息和宿主机是一样的,而不是配置后的容器的数据。(可以通过 lxcfs 修正)。
在运行 java 程序时,给容器内设置的内存为 4g,使用默认的 jvm 配置。而默认的 jvm 读取的内存是宿主机(可能大于 4g),这样就会出现 OOM 的情况。

六、解决的问题

1. 容器是如何进行隔离的?

在创建新进程时,通过 Namespace 技术,如 PID namespaces 等,实现隔离性。让运行后的容器仅能看到本身的内容。

比如,在容器运行时,会默认加上 PID, UTS, network, user, mount, IPC, cgroup 等 Namespace.

2. 容器是如何进行资源限制的?

通过 Linux Cgroup 技术,可为每个进程设定限制的 CPU,Memory 等资源,进而设置进程访问资源的上限。

3. 简述下 docker 的文件系统?

docker 的文件系统称为 rootfs,它的实现的想法来自与 Linux unionFS 。将不同的目录,挂载到一起,形成一个独立的视图。并且 docker 在此基础上引入了层的概念,解决了可重用性的问题。

在具体实现上,rootfs 的存储区分根据 linux 内核和 docker 本身的版本,分为 overlay2 , overlay, aufs, devicemapper 等。rootfs(镜像)其实就是多个层的叠加,当多层存在相同的文件时,上层的文件会将下层的文件覆盖掉。

4. 容器的启动过程?

  1. 指定 Linux Namespace 配置
  2. 设置指定的 Cgroups 参数
  3. 切换进程的根目录

5. 容器内运行多个应用的问题?

首先更正一个概念,我们都说容器是一个单进程的应用,其实这里的单进程不是指在容器中只允许着一个进程,而是指只有一个进程时可控的。在容器内当然可以使用 ping,ssh 等进程,但这些进程时不受 docker 控制的。

容器内的主进程,也就是 pid =1 的进程,一般是通过 DockerFile 中 ENTRYPOINT 或者 CMD 指定的。如果在一个容器内如果存在着多个服务(进程),就可能出现主进程正常运行,但是子进程退出挂掉的问题,而对于 docker 来说,仅仅控制主进程,无法对这种意外的情况作出处理,也就会出现,容器明明正常运行,但是服务已经挂掉的情况,这时编排系统就变得非常困难。而且多个服务,在也不容易进行排障和管理。

所以如果真的想要在容器内运行多个服务,一般会通过带有 systemd 或者 supervisord 这类工具进行管理,或者通过 --init 方法。其实这些方法的本质就是让多个服务的进程拥有同一个父进程。

但考虑到容器本身的设计,就是希望容器和服务能够同生命周期。所以这样做,有点背道而驰的意味。

控制(回收和生命周期的管理)

LangChain.js与Nuxt.js:AI全栈工程师的工程化实践指南 在现代Web开发中,前端工程化与AI能力集成已成为构建智能应用的关键。其核心原理在于,开发者无需深入底层模型训练,而是通过调用大模型API,结合工程化框架,将AI功能快速产品化。这一技术组合的价值在于,它能显著提升开发效率,降低AI应用的门槛,使前端开发者能够专注于用户体验与系统集成。典型的应用场景包括智能客服、内容分析与文档助手等交互式应用。本文聚焦于当前行业热点——利用LangChain.js框架进行AI能力编排,并结合Nuxt.js实现全栈部署,为希望向AI应用开发转型的前端工程师提供了一条清晰的实战 阅读详情

相关推荐

校园二手交易平台项目部署指南:SpringBoot多技术栈整合实践

在软件工程实践中,多技术栈整合是构建复杂应用系统的核心能力。其原理在于通过模块化设计,将不同编程语言和框架的优势组件协同工作,实现业务逻辑解耦与功能复用。这种架构模式的技术价值在于能够针对特定场景选择最优技术方案,例如利用Python进行数据爬取、Java SpringBoot构建稳健后端服务、Node.js处理实时通信,并结合小程序与安卓APP覆盖多端用户。在校园二手交易、电商平台、内容社区等应用场景中,多技术栈整合尤为常见,它能够高效支撑商品管理、用户交互、订单处理等核心业务流程。本文聚焦于一个典型的校

ctpaknc9526的博客 365

快速通关Kubernetes:10分钟解锁容器化部署与管理的秘籍

⽣产环境中经常需要有一些通⽤的配置初始化策略,比如权限统⼀设置,类似的活⼉交由sidecar 模式的容器器进行管理,这样的容器可以只处理通用性的需求,比如统⼀将⽇志⽬录的挂载采集策略进⾏编排,将日志挂载路路径规范化,采集统⼀化;CRD将K8S的能力和特定领域的软件的能力进行了整合,这个整合使得K8S具备了非常好的扩展空间。Obeserve--->Analyze--->Act 事件循环,k8s提供的控制器编程模型提供了可靠的基于资源的扩展协议和通用的编程模型,在该模型下可以扩展更多的通用定制化逻辑。

Reische的博客 142

基于Python与Django的新闻舆情分析系统:从数据采集到可视化实战

舆情分析是自然语言处理与数据挖掘领域的核心应用之一,其核心原理在于通过文本处理、情感计算与模式识别技术,将海量非结构化文本转化为结构化、可量化的洞察。这项技术的价值在于能够自动化地监测舆论动态、识别公众情绪、发现社会热点,为决策提供数据支持。在应用场景上,舆情分析广泛应用于品牌声誉管理、公共事务监测、市场趋势分析等领域。本文聚焦于一个结合了Python爬虫、Django后端框架、Scikit-learn机器学习库以及ECharts可视化技术的实战项目,完整演示了如何构建一个具备数据采集、情感分析、热点挖掘与

weixin_33736832的博客 383

Docker容器化解决方案(容器生命周期管理)

创建一个新的容器并运行一个命令。

杜小帅的博客 1016

容器化服务器:实现高效部署与管理的技术利器

容器化服务器是将应用程序及其所有依赖项打包到一个独立的、可移植的容器中的技术。每个容器都是一个独立的运行环境,其中包含应用程序、库、配置文件和系统工具。容器化服务器利用操作系统的虚拟化技术,在物理服务器上创建多个相互隔离的运行环境,使得应用程序能够以一种轻量级、可移植的方式运行。随着云计算和大数据时代的到来,服务器的部署和管理变得越来越关键。为了满足快速部署、可扩展性和弹性的需求,容器化技术逐渐成为企业和开发者的首选。本文将介绍容器化服务器的概念、优势以及如何使用源代码进行实现。二、容器化服务器的实现。

ZjbFullstack的博客 230

云计算从入门到云原生:一篇文章吃透虚拟化、容器化、IaC与编排

没有云计算的底座,现代 AI、EDA、CI/CD、私有大模型部署几乎都无从谈起。从 SGLang + LiteLLM 的私有部署,到 LangGraph 工作流的容器编排,再到 RAG 知识库的对象存储,全部都建立在虚拟化、容器化和编排这三大支柱之上。所以这门课与其说是"考试课",不如说是程序员的"工业基础知识"。传统 IT → 虚拟化 → IaaS → 容器化 → PaaS → 应用级 IaC → 容器编排 → 云原生下面进入正题。

元直的博客 296

Docker容器化:高效部署与管理应用

随着云计算和微服务架构的兴起,传统的应用部署方式逐渐暴露出诸多问题,如环境不一致、部署周期长、资源利用率低等。为解决这些问题,容器化技术应运而生。容器化技术将应用及其依赖打包成一个独立的单元,实现了环境一致性和快速部署。本文从多个方面详细阐述了Docker容器化如何实现高效部署与管理应用。Docker容器化技术的出现,解决了传统应用部署方式中的诸多问题,为软件开发和运维带来了巨大便利。未来,随着容器化技术的不断发展,我们有理由相信,它将在更多的场景中得到应用,推动整个IT行业的进步。建议。

2501_92487820的博客 571

置顶必读(1) | 《YOLOv26实战:从入门到深度优化》专栏导读与完整目录导航(持续更新中)

🏆 本文收录于 《YOLOv26实战:从入门到深度优化》 专栏。 本专栏系统梳理并持续复现 YOLOv26 官方特性、核心改进、多任务支持、部署优化与行业落地,内容坚持 持续更新 + 深度拆解 + 工程落地导向,不仅讲“怎么用”,更讲“为什么这样设计、如何真正落地到项目中”。

**My Coding Family** 9万+

Docker容器化技术:轻松部署与管理应用

Docker是一种开源的应用容器引擎,它允许开发者打包他们的应用以及应用的依赖包到一个可移植的容器中,然后发布到任何流行的Linux或Windows机器上。这种容器化的技术,使得应用可以在不同的环境中保持一致性,大大简化了应用的部署过程。本文详细阐述了Docker容器化技术如何轻松部署与管理应用。通过容器化技术,开发者可以简化应用的部署流程,提高应用的可靠性和可移植性。同时,容器编排和监控工具的出现,使得容器化管理变得更加高效和便捷。容器安全:随着容器技术的普及,容器安全问题日益凸显。

2501_92488732的博客 413

数字设计与计算机体系结构习题答案,数字设计和计算机体系结构习题答案DigitalDesignandComputerArchitecture.pdf...

数字设计和计算机体系结构习题答案DigitalDesignandComputerArchitecture.pdfDavid Money Harris and Sarah L. Harris, Digital Design and Computer Architecture, © 2007 by Elsevier Inc.Exercise SolutionsC H A P T E R ...

weixin_39851408的博客 1785

Cursor AI编程工具保姆级安装指南:从下载到中文界面设置(含免费额度说明)

本文提供Cursor AI编程工具的保姆级安装与设置教程。详细指导从官网下载、安装到中文界面切换的每一步,并重点说明其每月500次高级模型调用的免费额度策略。通过个性化设置与核心插件推荐,帮助开发者快速上手,提升AI辅助编程效率。

weixin_29191761的博客 672

Python后端工程师成长路线:从零到一掌握企业级开发核心技能

后端开发的核心在于构建健壮、可维护且能高效处理请求的服务,其技术栈围绕业务逻辑处理、数据持久化和接口提供展开。从原理层面看,这涉及HTTP协议、数据库系统、服务器架构等基础概念。掌握这些技术能显著提升系统的可靠性、扩展性和性能,对于构建高并发、高可用的互联网应用至关重要。在应用场景上,无论是电商平台、社交应用还是企业管理系统,都需要坚实的后端服务作为支撑。本文聚焦Python后端工程师的成长路径,系统梳理了从Python核心语法、Web框架(如Django/Flask)、数据库操作到RESTful API设

weixin_34192816的博客 324

Netapp FAS2750热备盘替换失败问题分析与解决

本文深入分析了Netapp FAS2750存储系统中热备盘替换失败的故障现象,揭示了磁盘分区属主不匹配导致数据同步无法启动的根本原因。通过详细的排查步骤和解决方案,帮助运维人员快速恢复aggr状态,并提供了长期预防措施和最佳实践建议,确保存储系统的高可用性。

weixin_33737774的博客 399

OpenClaw如何部署?

本书系统梳理当前智能体技术的发展脉络与应用趋势,全面解析智能体的构建原理与实战场景,帮助读者从零起步,掌握打造高效AI助手的核心方法。读者将跟随咖哥和小雪的脚步,踏上饶有趣味的Agent开发之旅,零距离接触GPT-4模型、OpenAI Assistants API、LangChain、LlamaIndex和MetaGPT等尖端技术,见证Agent在办公自动化、智能调度、知识整合以及检索增强生成(RAG)等领域的非凡表现,携手开启人工智能时代的无限可能,在人机协作的星空中共同探寻那颗最闪亮的Agent之星!

人邮异步社区 1462

DataGridView添加新行时在单元格绑定下拉列表DataGridViewComboBoxCell

效果图如下 先在界面上添加DataGridView,添加字段no、type、param 在lord事件中新建一行 dataGridView1.Rows.Add(); 在RowsAdded事件中操作新建的行 private void dataGridView1_RowsAdded_1(object sender, DataGridViewRowsAddedEventArgs...

wuqinglaohao的博客 1986

NOTE: When using the `ipython kernel` entry point, Ctrl-C will not work.解决方案

本文主要介绍了NOTE: When using the `ipython kernel` entry point, Ctrl-C will not work.解决方案,希望能对使用jupyter notebook的同学们有所帮助。 文章目录 1. 问题描述 2. 解决方案

weixin_43178406的博客 11万+

2026最新Linux运维零基础入门:免费体系化教程与实战路径

如果你正在寻找一套系统、完整且免费的Linux运维学习资源,并且希望从零开始,一步一个脚印地掌握从基础到进阶的所有核心技能,那么这篇文章就是为你准备的。这里整理了一份堪称“白嫖”级别的2026年最新Linux运维零基础入门教程,它不仅课程体系完整,还附带了配套的课件、文档和安装包,非常适合想要入行运维、转行或者系统提升技能的开发者。 这套资源的核心价值在于其结构化设计。它不是零散的博客文章或视频片段,而是一个从“计算机基础与Linux入门”开始,逐步深入到“云上基础运维”的完整学习路线。整个路径覆盖了Lin

weixin_30740295的博客 387

数据分析必问:Pandas面试题及参考答案

DataFrame是Pandas库中的一个核心数据结构,它类似于Excel中的表格,可以存储不同类型的数据。在Pandas中,抽样操作通常很简单,但是需要根据数据的特点和分析的需求来选择合适的抽样方法。数据标准化和归一化是数据预处理中常用的技术,目的是将数据调整到一个合适的范围内,以消除不同特征量纲和数值范围的差异,从而保证模型训练的有效性。CSV文件是一种文本文件,其中的数据以逗号分隔。不平衡数据集指的是数据集中各类别样本的数量差异较大的情况,这可能导致模型训练出现偏差,影响模型的泛化能力。

大模型大数据攻城狮的专栏 3009

大厂运维笔试复盘:从Linux到Kubernetes的核心考点与能力清单

运维工程师的招聘笔试,正在从单一的命令行考查转向对综合技术栈与实战思维的全面检验。无论是Linux文件系统与进程管理、TCP/IP与HTTP排障,还是MySQL索引与事务日志,这些基础能力始终是大厂筛选人才的第一道门槛。与此同时,容器化与云原生技术的普及,让kubernetes调用containerd、私有化运维、隧道运维管理等关键词成为笔试风向标,意味着运维岗位的知识边界已扩展至编排调度、监控告警与自动化平台。本文以一份知名互联网公司的校招运维真题为样本,拆解其出题逻辑,梳理高频考点背后的实际工作场景,并

chuannaoxuan4674的博客 350

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

置顶必读(1) | 《YOLOv9实战:从入门到深度优化》专栏导读与完整目录导航(持续更新中)

🏆 本文收录于 《YOLOv9实战:从入门到深度优化》 专栏。 本专栏系统梳理并持续复现 YOLOv9 全系列改进方案与实战案例,重点围绕 PGI、GELAN、可逆分支等核心创新展开,内容坚持 持续更新 + 深度拆解 + 工程落地导向,不仅讲“怎么改”,更讲“为什么这样改、如何真正落地到项目中”。

**My Coding Family** 4万+

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

美团2020运维校招笔试复盘:Linux、网络、数据库与K8s考点全解析

运维工程师的核心能力,往往体现在对Linux系统、网络协议、数据库与容器编排等基础组件的理解深度上。掌握命令行工具只是起点,真正关键的是构建从现象到根因的排查链路。例如,CPU飙升时如何通过top与jstack定位线程,海量TIME_WAIT连接怎样从连接池和内核参数双维度优化,以及MySQL索引失效的常见场景分析。容器时代,Kubernetes通过CRI调用containerd,再由runc创建进程的实体链路,已成为生产环境排障的基础认知。这些技术点不仅出现在大厂校招笔试中,更是日常保障高并发服务稳定性的

weixin_34208185的博客 353

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

软件开发自学路线图:从零基础到求职的系统规划与实践指南

软件开发是一个系统工程,其核心在于将问题转化为计算机可执行的逻辑指令。这一过程依赖于扎实的计算机基础,包括编程语言、数据结构、算法以及操作系统原理。掌握这些基础后,开发者能够构建高效、可靠的软件系统,其技术价值体现在提升开发效率、保障软件质量与可维护性。在实际应用中,无论是构建用户交互界面前端开发,还是实现硬件控制的嵌入式软件开发,都需要遵循明确的学习路径与工程实践方法。本文聚焦于如何规划一条高效的软件开发自学路线,特别针对前端开发学习路线和嵌入式软件开发学习路线这两个热门方向,提供从基础概念到项目实战的完

weixin_30240349的博客 398

Docker容器化管理技术

Docker 是一个开源项目 , 诞生于 2013 年初 , 最初dotCloud公司内部的一个业余项目 . 它基于 Google 公司推出的go语言实现 . 项目后来加入 Linux 基金会 , 遵从了 Apache2 .0 协议 , 项目代码在 GitHub 上进行维护 Docker 自开源后受到广泛的关注和讨论 , 以至于dotCloud公司后来都改名为 Docker Inc . Redhat 已经在其RHEL6 . 5 中集中支持 Docker;

薛之谦 1150

三、docker容器管理

### 1.Docker容器基本概念 #### 1.1 进程级别 运行中的容器是宿主机中的一个进程,相当于是一个开启的虚拟机,或者是个web服务 #### 1.2 由`Docker Daemon`管理 Docker Daemon 是Docker架构中运行在后台的守护进程,可分为Docker Server、Engine和Job三部分。与传统虚拟机架构相比。 Docker容器化其实就是将传统的`Hypervisor(虚拟机管理系统)`替换成了`Docker Daemon`,Docker Daemon统一管

wangleleb的博客 303
上一篇: 如何将Redis内存使用量降低一半?
下一篇: 为什么互联网大厂都愿意用Mybatis?MyBatis缓存特性你了解吗?
Java_Cappuccino
博客等级 码龄7年 17粉丝 64原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值