docker exec 是如何实现交互的

docker exec 命令的作用是进入到“容器内部”,并执行一些命令,那么它是如何实现把“容器内部”的 io 重定向到我们的终端(bash) 的呢? 基本原理 首先,要明白容器所依赖的内核 namespace 的概念,其实不存在“容器内部”,只要两个进程在相同的 namespace,那它们就相互可见,从用户的角度来说,也就是进入了容器內部。 nsenter nsenter 是一个命令行工具,它可以运行一个 binary,并且把它加入到指定的 namespace 中。 用法如下, nsenter -h nsenter -a -t <pid> <command> nsenter -m -u -i -n -p -t <pid> <command> 假设有一个 redis container 正在运行,通过 docker inspect --format {{.State.Pid}} 获取 pid, 假设为 2929。 然后运行 nsenter 命令: # nsenter -a -t 2929 ps aux USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND redis 1 0.0 0.0 52968 7744 ? Ssl May17 0:19 redis-server *:6379 root 93 0.0 0.0 7640 2748 ? R+ 05:47 0:00 ps aux 可以看到,ps 命令输出了 “容器內部” 的进程: redis 和 ps,符合我们的预期。 ...

2021-05-17 · Me

Docker 的 privileged 模式

无论是 docker 启动一个 container 还是在 k8s 中 deploy 一个 Pod 都可以指定 privileged 参数,之前在 Pod 的 spec YAML file 也里曾经用过,但是一直没有仔细想过加上这个参数后有什么不一样,今天就来研究一下。 首先来看一个最直观的对比,先运行一个没有 privileged 的容器: $ docker run --rm -it ubuntu:18.04 bash root@e6f5f42c5b7e:/# ls /dev/ console core fd full mqueue null ptmx pts root@e6f5f42c5b7e:/# fdisk -l 再来看看如果加上了 privileged 会有什么不一样: $ docker run --rm -it --privileged ubuntu:18.04 bash root@8e28f79eec9e:/# ls /dev/ tty11 tty2 tty28 tty36 tty44 tty52 tty60 ... ... root@8e28f79eec9e:/# fdisk -l Disk /dev/loop0: 97.1 MiB, 101777408 bytes, 198784 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes 不止能看到设备文件,甚至还能 mount 宿主机的文件系统, ...

2020-10-18 · Me

Orphan, Zombie and Docker

孤儿进程的产生 孤儿进程: 父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。通常,孤儿进程将被进程号为1的进程(进程号为 1 的是 init 进程)所收养,并由该进程调用 wait 对孤儿进程收尸。 #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <unistd.h> int main() { pid_t pid; pid = fork(); if (pid == 0) { printf("I'm child process, pid:%d ppid:%d\n", getpid(), getppid()); sleep(5); printf("I'm child process, pid:%d ppid:%d\n", getpid(), getppid()); } else { printf("I'm father process, pid:%d ppid:%d\n", getpid(), getppid()); sleep(1); printf("father process is exited.\n"); } return 0; } 运行结果如下所示: I'm father process, pid:25354 ppid:13981 I'm child process, pid:25355 ppid:25354 father process is exited. I'm child process, pid:25355 ppid:1 一般来说,孤儿进程并没有什么危害,因为当孤儿进程结束的时候,init 进程会调用 wait 来处理。 但是当到了 Docker 环境下是不是还是这样呢? 本文第三节再详细说明。 ...

2019-06-16 · Me

容器化博客的编译环境

前言 在上一篇博客 从 Wordpress 到 Jekyll 中,提到了把博客从原来的 Workpress 迁移到了 Jekyll, 开始用 Markdown 语法写博客正文,用 jekyll build 生成博客内容并部署到 Web 服务器。 最近这两天在考虑把 “jekyll build” 这个过程容器化,达到传说中 一次部署到处运行 的终极目标。 :-) 目标 废话不多说,开始折腾。 首先要制定一下具体的目标: jekyll build 是将 Markdown 语法写成的纯文本文件生成 html 文件,这也是我希望将它容器化的部分,因为我并不希望再次搭建 jekyll 的环境,只要有一个稳定能用的编译环境就可以了。 生成了 html 文件以后,拷贝到 nginx 的目录下,这样就可以通过浏览器访问博客内容了,一般来说也可以将 nginx 运行在容器里面。 但是我目前在学习 nginx 源码,希望时不时的能把我修改过的 nginx 部署到博客上,因此,不容器化 nginx 。 步骤 首先去 docker hub 上找了一个可用的镜像 jekyll/jekyll,这个镜像已经部署好了一个基本的 jekyll 环境。 docker pull jekyll/jekyll:latest 然后启动这个镜像并进入到容器中。 这一步如果非常清楚需要安装哪些软件的话可以用 Dockerfile 代替完成。我在这里直接进入到容器中是因为并不清楚需要安装哪些依赖软件,需要一步一步 debug。 docker run --rm --volume=/LOCAL_DIR:/srv/jekyll -it jekyll/jekyll /bin/bash ...

2018-05-16 · Me