如何删除docker镜像中已配置的volume

场景: 有个同学不知道因为啥,将容器内部的 /sys/fs/cgroup 挂载到了外面的某个目录; 但是这个目录是很有用的,不想随便被挂载,如何从image中去掉呢?

docker没有给出一个方便的方法, https://github.com/gdraheim/docker-copyedit 给了一个办法,原理如下:

每个image都是有一个manifest.json 文件的,相关配置信息都在这里了,但是你看不到image文件,更无从去谈修改manifest.json 文件了,所以:

  1. 先通过docker save 命令将image导出成tar文件:
  2. 在用tar命令解压文件
  3. 在解压后的文件中找到manifest.json 文件,这个文件可能不是你最终要修改的,里面的Config标识了配置文件的位置,应该就是该文件旁边的一个json文件
  4. 修改配置文件
  5. 重新打包image
  6. 导入image

我这里因为已经存在了同名的image,所以,旧的image的名字就被抢走了,但是ID没有变,新导入的image有自己新的ID

 

参考: https://github.com/gdraheim/docker-copyedit

linux命令 之 pgrep

每次查找关心的进程都去ps 再 grep显得好麻烦,而且这是一个非常常用的操作,所以,熟练使用pgrep将有效提高工作效率。

 

如果不看文档直接去pgrep 你关心的东西,可能得不到想要的效果,因为你关心的是进程的参数,而不是进程名,而且只输出pid,似乎也用处不大,所以,你可能非常关心两个选项:

-f: 模拟情况下,只匹配进程名(/proc/$pid/comm),使用-f选项可以匹配整个命令行(/proc/$pid/cmdline);

-a: 默认只输出pid, 使用-a选项可以输出pid 和整个命令行

 

所以,pgrep的正确姿势为:

 

高级用法:

当我们想在 a.sh 中判断a.sh脚本是否已经在执行时,我们可以通过 -o 选项来实现:

如果得到的pid就是自己,则说明没有已经在运行的a.sh;

 

按照ppid来查找:

Docker 不能访问外网的问题

往常,我使用docker的network=none ,然后使用pipework给容器添加一个外部可访问的IP,然后,容器就能访问外网了;

后来,我在openstack上创建的centos7虚拟机上安装docker,同样的方式启动的容器却无法访问外网,首先,centos7虚拟机的网卡去掉任何安全组,并设置为非管理状态; 检查centos7的ip_forward 是打开的,最终,发现差别就在于,原来的iptables规则中 FORWARD 的策略是ACCEPT ,而现在是FORWARD 策略是 DROP的;

问题: iptables的 FORWARD 的DROP策略是在哪个环节设置的呢?

 

参考docker 源码发现如下逻辑:

基本逻辑为:

如果本来是开启着ip转发的,就不会去设置iptables 的forward链的默认策略了;

如果本来没有开启ip转发的,就会去设置iptables 的forward链的默认策略。

显然,曾经的机器在docker启动前就已经设置了ip转发了, 而后来的机器在docker启动前还设置ip转发,虽然最终是都设置了IP转发,但是结果却不同;如果直接让docker来管理容器的网络,则docker会按照要求自动添加forward规则,然而,现在我们用的是pipework,就需要自己添加forward规则了,势必会麻烦一些;流氓一些的做法就是直接修改FORWORD 的默认策略。

tcp server in bash

我想通过nc+bash创建一个tcp server, nc负责收发数据,bash负责处理数据,如何将nc和bash结合起来呢?

思路1: 通过nc的-c选项实现

思路2: 只要能想办法将nc的标准输入和标准输入重定向给bash脚本就行了; 我们常见的管道、进程替换都只能同时做重定向标准输入或标准输出的其中一件事情; 如:

或:

这两个都是单向的

思路3: 我们通常使用exec来做重定向,似乎也比较麻烦

思路4: bash中提供了一个coproc关键字,似乎用在这里再合适不过了

 

方法1:

handler.sh

server.sh

这里利用了nc 的-c选项;

注意:

  • 这里的handler.sh 必须有可执行权限
  • handler.sh 必须在$PATH 里面,nc不参考当前目录
  • 为了规避这两个问题,可以这样:
  • 这种情况下,对于每一个连接都会启动一个-c指定的进程来处理,类似于cgi的模式;如果client 离开的太快,handler.sh echo时会遇到pipe broken的错误,需要处理一下
  • 需要仔细处理read ,避免client离开时,handler.sh还在无休止地循环,而且还占用 100% 的cpu

这里是通过两个文件来实现的,对于脚本程序来讲,如果一个文件能实现会方便很多;那么 nc 的 -c 选项能否接受一个bash 的function呢?直接写function显然是不行的,我们知道,环境变量是可以继承的,但是function 是不行的(参考: https://phpor.net/blog/post/9188),而且我们也不能把function赋值给一个变量; 或者可以这么实现:

但是,显得好不优雅; 而且,最大的问题就是,一不小心就可能成为fork炸弹💣

 

方法2:server.sh

注意:

  • 方法二的原理和方法一是不同的;这里的handler是一个常驻进程,不需要每次请求都fork一个handler,似乎更好一些,但是,handler无法区分不同的请求,client A可能接受到client B的请求的响应

问题:

  • 这个server可以服务很多请求,但是无法实现服务完一个请求后主动断开
  • 如何nc先退出了,handler如何判断

 

参考:

总结:

  • bash写个简版的东西还挺方便,写完善就不好弄了
  • 方法一似乎更加合理一些
  • 千万别用bash来实现tcpserver

 

bash 获取所有pid

 

ls 可以list /proc 目录下所有的pid,但是线程id是list不到的,如:

我们 ls /proc 的时候,只能看到 24 这个目录,看不到25 26 27 这些目录,那么线程的信息如何访问到呢?

实际上,虽然我们不能ls /proc 看到线程,但是,如果有了线程id,还是可以通过 /proc/$thread_id 来访问的,如:

count words in bash without wc

如何计算字符串中单词的数量,但是不使用wc? eg:

如果字符串的内容在文件中,则可以直接 read -a arr 来读入到指定数组中,然后再获取数组的长度即可

 

参考:

cfree ( free in container)