This commit is contained in:
周伟
2022-05-11 19:04:14 +08:00
parent 9440ac7291
commit d9c5ffd627
826 changed files with 0 additions and 481675 deletions

View File

@@ -25,13 +25,7 @@
<meta name="generator" content="Hexo 4.2.0">
</head>
<body>
<div class="book-container">
<div class="book-sidebar">
@@ -55,385 +49,196 @@
<li><a href="/" class="current-tab">首页</a></li>
</ul>
<ul class="uncollapsible">
<li><a href="../">上一级</a></li>
</ul>
<ul class="uncollapsible">
<li>
<a href="/专栏/容器实战高手课/00 开篇词 一个态度两个步骤,成为容器实战高手.md.html">00 开篇词 一个态度两个步骤,成为容器实战高手.md.html</a>
</li>
<li>
<a class="current-tab" href="/专栏/容器实战高手课/01 认识容器:容器的基本操作和实现原理.md.html">01 认识容器:容器的基本操作和实现原理.md.html</a>
</li>
<li>
<a href="/专栏/容器实战高手课/02 理解进程1为什么我在容器中不能kill 1号进程.md.html">02 理解进程1为什么我在容器中不能kill 1号进程.md.html</a>
</li>
<li>
<a href="/专栏/容器实战高手课/03 理解进程2为什么我的容器里有这么多僵尸进程.md.html">03 理解进程2为什么我的容器里有这么多僵尸进程.md.html</a>
</li>
<li>
<a href="/专栏/容器实战高手课/04 理解进程3为什么我在容器中的进程被强制杀死了.md.html">04 理解进程3为什么我在容器中的进程被强制杀死了.md.html</a>
</li>
<li>
<a href="/专栏/容器实战高手课/05 容器CPU1怎么限制容器的CPU使用.md.html">05 容器CPU1怎么限制容器的CPU使用.md.html</a>
</li>
<li>
<a href="/专栏/容器实战高手课/06 容器CPU2如何正确地拿到容器CPU的开销.md.html">06 容器CPU2如何正确地拿到容器CPU的开销.md.html</a>
</li>
<li>
<a href="/专栏/容器实战高手课/07 Load Average加了CPU Cgroup限制为什么我的容器还是很慢.md.html">07 Load Average加了CPU Cgroup限制为什么我的容器还是很慢.md.html</a>
</li>
<li>
<a href="/专栏/容器实战高手课/08 容器内存:我的容器为什么被杀了?.md.html">08 容器内存:我的容器为什么被杀了?.md.html</a>
</li>
<li>
<a href="/专栏/容器实战高手课/09 Page Cache为什么我的容器内存使用量总是在临界点.md.html">09 Page Cache为什么我的容器内存使用量总是在临界点.md.html</a>
</li>
<li>
<a href="/专栏/容器实战高手课/10 Swap容器可以使用Swap空间吗.md.html">10 Swap容器可以使用Swap空间吗.md.html</a>
</li>
<li>
<a href="/专栏/容器实战高手课/11 容器文件系统:我在容器中读写文件怎么变慢了.md.html">11 容器文件系统:我在容器中读写文件怎么变慢了.md.html</a>
</li>
<li>
<a href="/专栏/容器实战高手课/12 容器文件Quota容器为什么把宿主机的磁盘写满了.md.html">12 容器文件Quota容器为什么把宿主机的磁盘写满了.md.html</a>
</li>
<li>
<a href="/专栏/容器实战高手课/13 容器磁盘限速:我的容器里磁盘读写为什么不稳定.md.html">13 容器磁盘限速:我的容器里磁盘读写为什么不稳定.md.html</a>
</li>
<li>
<a href="/专栏/容器实战高手课/14 容器中的内存与IO容器写文件的延时为什么波动很大.md.html">14 容器中的内存与IO容器写文件的延时为什么波动很大.md.html</a>
</li>
<li>
<a href="/专栏/容器实战高手课/15 容器网络我修改了procsysnet下的参数为什么在容器中不起效.md.html">15 容器网络我修改了procsysnet下的参数为什么在容器中不起效.md.html</a>
</li>
<li>
<a href="/专栏/容器实战高手课/16 容器网络配置1容器网络不通了要怎么调试.md.html">16 容器网络配置1容器网络不通了要怎么调试.md.html</a>
</li>
<li>
<a href="/专栏/容器实战高手课/17 容器网络配置2容器网络延时要比宿主机上的高吗.md.html">17 容器网络配置2容器网络延时要比宿主机上的高吗.md.html</a>
</li>
<li>
<a href="/专栏/容器实战高手课/18 容器网络配置3容器中的网络乱序包怎么这么高.md.html">18 容器网络配置3容器中的网络乱序包怎么这么高.md.html</a>
</li>
<li>
<a href="/专栏/容器实战高手课/19 容器安全1我的容器真的需要privileged权限吗.md.html">19 容器安全1我的容器真的需要privileged权限吗.md.html</a>
</li>
<li>
<a href="/专栏/容器实战高手课/20 容器安全2在容器中我不以root用户来运行程序可以吗.md.html">20 容器安全2在容器中我不以root用户来运行程序可以吗.md.html</a>
</li>
<li>
<a href="/专栏/容器实战高手课/加餐01 案例分析怎么解决海量IPVS规则带来的网络延时抖动问题.md.html">加餐01 案例分析怎么解决海量IPVS规则带来的网络延时抖动问题.md.html</a>
</li>
<li>
<a href="/专栏/容器实战高手课/加餐02 理解perf怎么用perf聚焦热点函数.md.html">加餐02 理解perf怎么用perf聚焦热点函数.md.html</a>
</li>
<li>
<a href="/专栏/容器实战高手课/加餐03 理解ftrace1怎么应用ftrace查看长延时内核函数.md.html">加餐03 理解ftrace1怎么应用ftrace查看长延时内核函数.md.html</a>
</li>
<li>
<a href="/专栏/容器实战高手课/加餐04 理解ftrace2怎么理解ftrace背后的技术tracepoint和kprobe.md.html">加餐04 理解ftrace2怎么理解ftrace背后的技术tracepoint和kprobe.md.html</a>
</li>
<li>
<a href="/专栏/容器实战高手课/加餐05 eBPF怎么更加深入地查看内核中的函数.md.html">加餐05 eBPF怎么更加深入地查看内核中的函数.md.html</a>
</li>
<li>
<a href="/专栏/容器实战高手课/加餐06 BCC入门eBPF的前端工具.md.html">加餐06 BCC入门eBPF的前端工具.md.html</a>
</li>
<li>
<a href="/专栏/容器实战高手课/加餐福利 课后思考题答案合集.md.html">加餐福利 课后思考题答案合集.md.html</a>
</li>
<li>
<a href="/专栏/容器实战高手课/结束语 跳出舒适区,突破思考的惰性.md.html">结束语 跳出舒适区,突破思考的惰性.md.html</a>
</li>
</ul>
</div>
</div>
<div class="sidebar-toggle" onclick="sidebar_toggle()" onmouseover="add_inner()" onmouseleave="remove_inner()">
<div class="sidebar-toggle-inner"></div>
</div>
<script>
function add_inner() {
@@ -443,9 +248,6 @@
inner.classList.add('show')
}
function remove_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
@@ -453,9 +255,6 @@
inner.classList.remove('show')
}
function sidebar_toggle() {
let sidebar_toggle = document.querySelector('.sidebar-toggle')
@@ -485,9 +284,6 @@
}
function open_sidebar() {
let sidebar = document.querySelector('.book-sidebar')
@@ -511,13 +307,7 @@ function hide_canvas() {
overlay.classList.remove('show')
}
</script>
<div class="off-canvas-content">
<div class="columns">
@@ -579,9 +369,6 @@ function hide_canvas() {
<pre><code>
# docker run -d centos/httpd:latest
</code></pre>
<p>这命令也很简单run 的意思就是要启动一个容器, -d 参数里 d 是 Daemon 的首字母,也就是让容器在后台运行。</p>
@@ -621,9 +408,6 @@ COPY file1 /var/www/html/
ADD file2.tar.gz /var/www/html/
CMD [&quot;/sbin/httpd&quot;, &quot;-D&quot;, &quot;FOREGROUND&quot;]
</code></pre>
<p>我们看下它做了哪几件事:在一个 centos 的基准镜像上安装好 httpd 的包,然后在 httpd 提供文件服务的配置目录下,把需要对外提供的文件 file1 和 file2 拷贝过去,最后指定容器启动以后,需要自动启动的 httpd 服务。</p>
@@ -639,9 +423,6 @@ CMD [&quot;/sbin/httpd&quot;, &quot;-D&quot;, &quot;FOREGROUND&quot;]
<pre><code>
# docker build -t registry/httpd:v1 -f ./Dockerfile .
</code></pre>
<p>docker build 执行成功之后,我们再运行 docker images 这个命令,就可以看到生成的镜像了。</p>
@@ -649,15 +430,9 @@ CMD [&quot;/sbin/httpd&quot;, &quot;-D&quot;, &quot;FOREGROUND&quot;]
<pre><code>
# docker images
REPOSITORY TAG IMAGEID CREATED SIZE
registry/httpd v1 c682fc3d4b9a 4 seconds ago 277MB
</code></pre>
<h2>启动一个容器 (Container)</h2>
@@ -667,9 +442,6 @@ registry/httpd v1 c682fc3d4b9a 4 seconds ago 277MB
<pre><code>
# docker run -d registry/httpd:v1
</code></pre>
<p>容器启动完成后,我们可以用 docker ps 命令来查看这个已经启动的容器:</p>
@@ -677,15 +449,9 @@ registry/httpd v1 c682fc3d4b9a 4 seconds ago 277MB
<pre><code>
# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c5a9ff78d9c1 registry/httpd:v1 &quot;/sbin/httpd -D FORE…&quot; 2 seconds ago Up 2 seconds loving_jackson
</code></pre>
<p>在前面介绍 Dockerfile 的时候,我们说过做这个镜像是用来提供 HTTP 服务的,也就是让用户可以下载 file1、file2 这两个文件。</p>
@@ -717,9 +483,6 @@ apache 7 1 0 01:59 ? 00:00:00 /sbin/httpd -D FOREGROUND
apache 8 1 0 01:59 ? 00:00:00 /sbin/httpd -D FOREGROUND
apache 9 1 0 01:59 ? 00:00:00 /sbin/httpd -D FOREGROUND
</code></pre>
<p>这里我解释一下,在这个 docker exec 后面紧跟着的 ID 表示容器的 ID这个 ID 就是我们之前运行 docker ps 查看过那个容器,容器的 ID 值是 c5a9ff78d9c1 。在这个 ID 值的后面,就是我们要在容器空间里运行的 ps -ef 命令。</p>
@@ -737,9 +500,6 @@ apache 9 1 0 01:59 ? 00:00:00 /sbin/httpd -D FOREGROUND
file1
file2
</code></pre>
<p>到这里我们完成了第一步的验证,进入到容器的运行空间里,验证了 httpd 服务已经启动,配置文件也是正确的。</p>
@@ -755,9 +515,6 @@ file2
<pre><code>
# docker exec c5a9ff78d9c1 ip addr
1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
@@ -783,25 +540,10 @@ file2
<pre><code>
# curl -L -O http://172.17.0.2/file2
% Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed
100 6 100 6 0 0 1500 0 --:--:-- --:--:-- --:--:-- 1500
# ls
file2
</code></pre>
<p>上面的步骤完成之后,我们的第二步验证,用 curl 下载 httpd 服务提供的文件也成功了。</p>
@@ -833,9 +575,6 @@ file2
<pre><code>
# docker exec c5a9ff78d9c1 ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 01:59 ? 00:00:00 /sbin/httpd -D FOREGROUND
@@ -847,9 +586,6 @@ apache 7 1 0 01:59 ? 00:00:00 /sbin/httpd -D FOREGROUND
apache 8 1 0 01:59 ? 00:00:00 /sbin/httpd -D FOREGROUND
apache 9 1 0 01:59 ? 00:00:00 /sbin/httpd -D FOREGROUND
</code></pre>
<p>如果我们不用 docker exec直接在宿主机上运行 ps -ef就会看到很多进程。如果我们运行一下 grep httpd ,同样可以看到这 5 个 httpd 的进程:</p>
@@ -857,9 +593,6 @@ apache 9 1 0 01:59 ? 00:00:00 /sbin/httpd -D FOREGROUND
<pre><code>
# ps -ef | grep httpd
UID PID PPID C STIME TTY TIME CMD
root 20731 20684 0 18:59 ? 00:00:01 /sbin/httpd -D FOREGROUND
@@ -871,9 +604,6 @@ root 20731 20684 0 18:59 ? 00:00:01 /sbin/httpd -D FOREGROUND
48 20789 20731 0 18:59 ? 00:00:05 /sbin/httpd -D FOREGROUND
48 20791 20731 0 18:59 ? 00:00:05 /sbin/httpd -D FOREGROUN
</code></pre>
<p>这两组输出结果到底有什么差别呢,你可以仔细做个对比,最大的不同就是进程的 PID 不一样。那为什么 PID 会不同呢?或者说,运行 docker exec c5a9ff78d9c1 ps -ef 和 ps -ef 实质的区别在哪里呢?</p>
@@ -909,9 +639,6 @@ root 20731 20684 0 18:59 ? 00:00:01 /sbin/httpd -D FOREGROUND
valid_lft forever preferred_lft forever
168: <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="4025342870002926717679">[email&#160;protected]</a>: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
@@ -919,9 +646,6 @@ root 20731 20684 0 18:59 ? 00:00:01 /sbin/httpd -D FOREGROUND
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
</code></pre>
<p>我们还可以运行 docker exec c5a9ff78d9c1 ls/ 查看容器中的根文件系统rootfs。然后你会发现它和宿主机上的根文件系统也是不一样的。容器中的根文件系统其实就是我们做的镜像。</p>
@@ -977,9 +701,6 @@ root 20731 20684 0 18:59 ? 00:00:01 /sbin/httpd -D FOREGROUND
<p>具体操作是这样的我们把2* 1024 * 1024 * 1024 = 2147483648这个值写入 memory Cgroup 控制组中的 memory.limit_in_bytes 里这样设置后cgroup.procs 里面所有进程 Memory 使用量之和,最大也不会超过 2GB。</p>
<pre><code># cd /sys/fs/cgroup/memory/system.slice/docker-c5a9ff78d9c1fedd52511e18fdbd26357250719fa0d128349547a50fad7c5de9.scope
# cat cgroup.procs
20731
@@ -991,17 +712,11 @@ root 20731 20684 0 18:59 ? 00:00:01 /sbin/httpd -D FOREGROUND
20789
20791
# echo 2147483648 &gt; memory.limit_in_bytes
# cat memory.limit_in_bytes
2147483648
</code></pre>
<p>刚刚我们通过 memory Cgroups 定义了容器的 memory 可以使用的最大值。其他的子系统稍微复杂一些,但用法也和 memory 类似,我们在后面的课程中会结合具体的实例来详细解释其他的 Cgroups。</p>
@@ -1065,9 +780,6 @@ root 20731 20684 0 18:59 ? 00:00:01 /sbin/httpd -D FOREGROUND
</div>
</div>
</div>
</div>
@@ -1075,9 +787,6 @@ root 20731 20684 0 18:59 ? 00:00:01 /sbin/httpd -D FOREGROUND
</div>
</div>
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
</div>
@@ -1093,17 +802,11 @@ root 20731 20684 0 18:59 ? 00:00:01 /sbin/httpd -D FOREGROUND
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'G-NPSEEVD756');
@@ -1129,9 +832,6 @@ root 20731 20684 0 18:59 ? 00:00:01 /sbin/httpd -D FOREGROUND
setCookie("lastPath", path)
}
function setCookie(cname, cvalue) {
var d = new Date();
@@ -1143,9 +843,6 @@ root 20731 20684 0 18:59 ? 00:00:01 /sbin/httpd -D FOREGROUND
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
}
function getCookie(cname) {
var name = cname + "=";
@@ -1163,12 +860,6 @@ root 20731 20684 0 18:59 ? 00:00:01 /sbin/httpd -D FOREGROUND
return "";
}
</script>
</html>