关于docker的15个小tip(技巧)

1. 获取最近运行容器的id

这是我们经常会用到的一个操作,按照官方示例,你可以这样做(环境ubuntu):

$ ID=$(docker run ubuntu echo hello world)

hello world

$ docker commit $ID helloworld

fd08a884dc79

这种方式在编写脚本的时候很有用,比如你想在脚本中批量获取id,然后进一步操作。但是这种方式要求你必须给ID赋值,如果是直接敲命令,这样做就不太方便了。 这时,你可以换一种方式:

$ alias dl='docker ps -l -q'

$ docker run ubuntu echo hello world

hello world

$ dl

1904cf045887

$ docker commit `dl` helloworld

fd08a884dc79

docker ps -l -q命令将返回最近运行的容器的id,通过设置别名(alias),dl命令就是获取最近容器的id。这样,就无需再输入冗长的docker ps -l -q命令了。通过两个斜引号“,可以获取dl命令的值,也就是最近运行的容器的id。

2.尽量在Dockerfile中指定要安装的软件,而不用Docker容器的shell直接安装软件

说实话,我有时候也喜欢在shell中安装软件,也许你也一样,喜欢在shell中把所有软件安装都搞定。但是,搞来搞去,最后还是发现,你还是需要在Doockerfile中指定安装文件。在shell中安装软件,你要这样做:

$ docker run -i -t ubuntu bash #登陆到docker容器

root@db0c3967abf8:/#

然后输入下面的命令来安装文件:

apt-get install postgresql 

然后再调用exit:

root@db0c3978abf8:/# exit

退出docker容器,再给docker commit命令传递一个复杂的JSON字符串来提交新的镜像:

$ docker commit -run=”{“Cmd”:[“postgres”,”-too -many -opts”] }” `dl` postgres

太麻烦了,不是吗?还是在Dockerfile中指定安装文件吧,只要两个步骤:

1.在一个小巧的Dockerfile中,指定当前操作的镜像为FROM命令的参数

2.然后在Dockerfile中指定一些docker的命令,如CMD, ENTERPOINT, VOLUME等等来指定安装的软件

3.超-超-超级用户

你可能需要一直用超级用户来操作docker,就像早期示例里一直提示的:

# 添加docker用户组

$ sudo groupadd docker

# 把自己加到docker用户组中

$ sudo gpasswd -a myusername docker

# 重启docker后台服务

$ sudo service docker restart

# 注销,然后再登陆

$ exit

Wow!连续三个sudo!三次化身“超级用户”,真可谓是“超-超-超级用户”啊!别担心,设置完毕,以后你就再也不用打那么多sudo了!

4. 清理垃圾

如果你想删除所有停止运行的容器,用这个命令:

$ docker rm $(docker ps -a -q)

顺便说一句,docker ps命令很慢,不知道为啥这么慢,按理说Go语言是很快的啊。docker ps -a -q命令列出所有容器的id,然后根据id删除容器。docker rm命令遇到正在运行的容器就会失效,所以这个命令完美的删除了所有没在运行的容器。

5. docker inspect输出结果的解析利器:jq

要对docker inspect的输出结果进行过滤,一般情况下,用grep命令,你需要这样操作:

$docker inspect `dl` | grep IPAddress | cut -d ‘“‘ -f 4 172.17.0.52 

哦!看上去很复杂,用jq吧,专业解析docker inspect输出结果,具有更强的可读性,方便易用:

$docker inspect `dl` | jq -r ‘.[0].NetworkSettings.IPAddress' 172.17.0.52 

其中第一个'.'代表所有的结果。'[0]'代表数组的第一个元素。就像JavaScript访问一个JSON对象一样,简单方便。

6.镜像有哪些环境变量?

有时候,你需要知道自己创建的镜像有哪些环境变量。简单!只要这样:

$ docker run ubuntu env 

输出结果如下:

HOME=/

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

container=lxc

HOSTNAME=5e1560b7f757

调用env查看环境变量,对于后面要讲到的“链接”(-link)很有用,在连接两个容器时候需要用到这些环境变量,具体请看最后一个要点“链接”。

7.RUN命令 vs CMD命令

Docker的新手用户比较容易混淆RUN和CMD这两个命令。

RUN命令在构建(Build)Docker时执行,这时CMD命令不执行。CMD命令在RUN命令执行时才执行。我们来理清关系,假设Dockerfile内容如下:

FROM thelanddownunder

MAINTAINER crocdundee

我们要向系统中安装一些软件,那么:

# docker build将会执行下面的命令:

RUN apt-get update

RUN apt-get install softwares

# dokcer run默认执行下面的命令:

CMD [“softwares”]

Build时执行RUN,RUN时执行CMD,也就是说,CMD才是镜像最终执行的命令。

8.CMD命令 vs ENTRYPOINT命令

又是两条容易混淆的命令!具体细节我们就不说了,举个例子,假设一个容器的Dockerfile指定CMD命令,如下:

FROM ubuntu

CMD [“echo”]

另一个容器的Dockerfile指定ENTRYPOINT命令,如下:

FROM ubuntu

ENTRYPOINT [“echo”]

运行第一个容器:

docker run image1 echo hello

得到的结果:

hello

运行第二个容器:

docker run image2 echo hello

得到的结果:

echo hello

看到不同了吧?实际上,CMD命令是可覆盖的,docker run后面输入的命令与CMD指定的命令匹配时,会把CMD指定的命令替换成docker run中带的命令。而ENTRYPOINT指定的命令只是一个“入口”,docker run后面的内容会全部传给这个“入口”,而不是进行命令的替换,所以得到的结果就是“echo hello”。

9.Docker容器有自己的IP地址吗?

刚接触Docker的人或许会有这样的疑问:Docker容器有自己的IP地址吗?Docker容器是一个进程?还是一个虚拟机?嗯…也许两者兼 具?哈哈,其实,Docker容器确实有自己的IP,就像一个具有IP的进程。只要分别在主机和Docker容器中执行查看ip的命令就知道了。

查看主机的ip:

$ ip -4 -o addr show eth0 

得到结果:

2: eth0 inet 162.243.139.222/24

查看Docker容器的ip:

$ docker run ubuntu ip -r -o addr show eth0

得到结果:

149: eth0   inet 172.17.0.43/16

两者并不相同,说明Docker容器有自己的ip。

10.基于命令行的瘦客户端,使用UNIX Socket和Docker后台服务的REST接口进行通信

Docker默认是用UNIX socket通信的,一直到大概0.5、0.6的版本还是用端口来通信,但现在则改成UNIX socket,所以从外部无法控制Docker容器的内部细节。下面我们来搞点有趣的事情,从主机链接到docker的UNIX socket:

# 像HTTP客户端一样连接到UNIX socket

$ nc -U / /var/run/docker.sock

连接成功后,输入:

GET /images/json HTTP/1.1 

输入后连敲两个回车,第二个回车表示输入结束。然后,得到的结果应该是:

HTTP/1.1 200 OK

Content-Type: application/json

Date: Tue, 05 Nov 2013 23:18:09 GMT

Transfer-Encoding: chunked

16aa

[{“Repository”:”postgres”,”Tag”:”......

有一天,我不小心把提交的名称打错了,名字开头打成”-xxx”(我把命令和选项的顺序搞混了),所以当我删除的时候出了问题,docker rm -xxx,会把-xxx当成参数而不是镜像的名称。所以我只得通过socket直接连到容器来调用REST Server把错误的东西删掉。

11.把镜像的依赖关系绘制成图

docker images命令有一个很拉风的选项:-viz,可以把镜像的依赖关系绘制成图并通过管道符号保存到图片文件:

# 生成一个依赖关系的图表

$ docker images -viz | dot -T png -o docker.png

这样,主机的当前路径下就生成了一张png图,然后,用python开启一个微型的HTTP服务器:

python -m SimpleHTTPServer

然后在别的机器上用浏览器打开:http://machinename:8000/docker.png

OK,依赖关系一目了然!

(译者注:要使用dot命令,主机要安装graphviz包。另外,如果主机ip没有绑定域名,machinename换成主机的ip即可。)

12.Docker把东西都存到哪里去了?

Docker实际上把所有东西都放到/var/lib/docker路径下了。切换成super用户,到/var/lib/docker下看看,你能学到很多有趣的东西。执行下面的命令:

$ sudo su

# cd /var/lib/docker

# ls -F

containers/ graph/ repositories volumes/

可以看到不少目录,containers目录当然就是存放容器(container)了,graph目录存放镜像,文件层(file system layer)存放在graph/imageid/layer路径下,这样你就可以看看文件层里到底有哪些东西,利用这种层级结构可以清楚的看到文件层是如 何一层一层叠加起来的。

13.Docker源代码:Go, Go, Go, Golang!

Docker的源代码全部是用Go语言写的。Go是一门非常酷的语言。其实,不只是Docker,很多优秀的软件都是用Go写的。对我来说,Docker源文件中,有4个是我非常喜欢阅读的:

commands.go

docker的命令行接口,是对REST API的一个轻量级封装。Docker团队不希望在命令中出现逻辑,因此commands.go只是向REST API发送指令,确保其较小的颗粒性。

api.go

REST API的路由(接受commands.go中的请求,转发到server.go)

server.go

大部分REST API的实现

buildfile.go

Dockerfile的解析器

有的伙计惊叹”Wow!Docker是怎么实现的?!我无法理解!”没关系,Docker是开源软件,去看它的源代码就可以了。如果你不太清楚Dockerfile中的命令是怎么回事,直接去看buildfile.go就明白了。

14.运行几个Docker后台程序,再退出容器,会发生什么?

OK,倒数第二个要点。如果在Docker中运行几个后台程序,再退出Docker容器,会发生什么?答案是:不要这么做!因为这样做后台程序就全丢了。

Dockerfile中用RUN命令去开启一个后台程序,如:

RUN pg_ctl start

这样的话,RUN命令开启的后台程序就会丢失。调用容器的bash连到容器的shell:

$ docker run -i -t postgresimage bash

然后调用 ps aux查看进程,你会发现postgres的进程并没有跑起来。 RUN命令会影响文件系统。因此,不要再Dockerfile中用启动后台程序,要把后台程序启动成前台进程。或者,像一些高手提议的那样,写一个启动脚 本,在脚本中启动这些后台程序或进程。

15.容器之间进行友好沟通:链接

这是最拉风的功能!我把它留到最后压轴!这是0.6.5中最重要的新功能,我们前面已经提过两次了。运行一个容器,给它一个名称,在下面的例子中,我们通过-name参数给容器指定名称”loldb”:

$ docker run -d -name loldb loldbimage

再运行另一个容器,加上-link参数来连接到第一个容器(别名为loldb),并给第二个容器也指定一个别名(这里用的是cheez):

$ docker run -link /loldb:cheez otherimage env

顺便得到cheez的环境变量:

CHEEZ_PORT=tcp://172.17.0.8:6379

CHEEZ_PORT_1337_TCP=tcp://172.17.0.8.6379

CHEEZ_PORT_1337_TCP_ADDR=tcp://172.17.0.12

CHEEZ_PORT_1337_TCP_PORT=6379

CHEEZ_PORT_1337_TCP_PROTO=tcp

这样,我们就在两个容器间建立起一个网络通道(bridge),基于此,我们可以建立一个类似rails的程序:一个容器可以访问数据库容器而不对外暴露其他接口。非常酷!数据库容器只需要知道第一个容器的别名(在本例中为cheez)和要打开的端口号。所以数据库容器也可以env命令来查看这个端口是否打开。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Docker 容器虚拟化的实用技巧总结

    服务器虚拟化指的是在操作系统与硬件之间加一层,叫做hypervisor层,对下控制硬件,对上承载操作系统,操作系统os以文件形式封装运行,称为虚拟机,主要解决的问题是硬件利用率和灵活性的问题,常见的方案为vmware vsphere,xen,kvm,hyper-v..容器虚拟化指的是在os上将应用打包以进程的形式运行,应用和应用间非完全隔离,但是更轻量,效率高,lxc和docker都可以称为容器级虚拟化,区别在于docker可以理解为经过精美封装过更加好用的lxc,有更好的接口和更完善的配套.

  • docker日常使用的实用小技巧总结(推荐)

    前言 Docker 是一个能够把开发应用程序自动部署到容器的开源引擎.它由Docker公司的团队编写,基于Apache 2.0开源协议授权.它提供了一个简单.轻量的建模方式,使开发生命周期更高效快速,鼓励了面向服务的架构设计.Docker 项目的目标是实现轻量级的操作系统虚拟化解决方案. Docker 的基础是 Linux 容器(LXC)等技术.在 LXC 的基础上 Docker 进行了进一步的封装,让用户不需要去关心容器的管理,使得操作更为简便.用户操作 Docker 的容器就像操作一个快速轻

  • Docker 实用技巧总结

    我有机会建立一个以Docker为基础的微服务架构在我现在的工作中,很多人都会分享他们使用Docker的心得,我想我也不会例外.因此我总结了一些,可能你会在日常使用Docker的时候会用到. 1. 一台主机部署多个Docker实例 如果你想运行多个Docker 容器在一台主机上,如果要设置不同的TLS设置,网络设置,日志设置和存储驱动程序特定的容器,这是特别有用的.例如,我们目前正在运行一个标准设立两个Docker守护进程.一运行consul提供DNS解析,并作为群集存储为其他Docker 容器.

  • Docker 技巧之删除Docker容器和镜像

    公司业务在生产环境100多台服务器上用了docker,已经有大半年了,可是最近发现,每个服务器上的各种镜像好多好乱,就想批量删除镜像,需要的来看一下把. 删除所有未运行 Docker 容器 docker rm $(docker ps -a -q) 删除所有 Docker 镜像 删除所有未打 tag 的镜像 docker rmi $(docker images -q | awk '/^<none>/ { print $3 }') 删除所有镜像 docker rmi $(docker images

  • 关于docker的15个小tip(技巧)

    1. 获取最近运行容器的id 这是我们经常会用到的一个操作,按照官方示例,你可以这样做(环境ubuntu): $ ID=$(docker run ubuntu echo hello world) hello world $ docker commit $ID helloworld fd08a884dc79 这种方式在编写脚本的时候很有用,比如你想在脚本中批量获取id,然后进一步操作.但是这种方式要求你必须给ID赋值,如果是直接敲命令,这样做就不太方便了. 这时,你可以换一种方式: $ alias

  • 优化Docker镜像安全性的12个技巧总结

    目录 1前言 2避免泄露构建密钥 多阶段构建 BuildKit的密钥 题外话:不要推送在开发机上构建的镜像 3以非root用户身份运行 4使用最新的基础镜像构建和更新系统包 背景知识 6对你的镜像进行漏洞扫描 7扫描你的Dockerfile是否违反了最佳实践 8不要对DockerHub使用Docker内容信任 9扫描你自己的代码是否有安全问题 10使用docker-slim来删除不必要的文件 11使用最小的基础镜像 12使用受信任的基础镜像 背景知识 13测试你的镜像是否能在降低能力的情况下工作

  • Docker常用命令与小技巧汇总

    安装脚本 Ubuntu / Centos Debian的安装貌似有问题, 需要解决安装源的问题. curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh --mirror Aliyun / AzureChinaCloud 如果在海外的AWS或者GCP等云服务器厂商, --mirror 自然不需要加上去了. Centos在运行完成之后, 还需要手动的 sudo systemctl start docker.s

  • 微信小程序技巧之show内容展示,上传文件编码问题

    show内容展示 尝试用微信小程序的template组件实现.同时,尝试页面间转跳时传参,在目标页面引入模板文件实现 写的更少,做的更多 篇幅有限详细代码此处省略 <view class="show-warp"> <block wx:for="{{discuss}}" wx:key="index"> <template is="discuss" data="{{item}}"&

  • Android分享微信小程序技巧之图片优化

    前言 小菜上周接入了微信分享小程序的入口,基本功能实现都没问题,有需要的朋友可以了解一下 Android 分享微信小程序失败二三事,虽然功能都正常,但整体测试发现图片展示效果不佳.于是小菜整理了一个简单的小方法处理一下图片! 微信规定,分享小程序展示的图片应该在 128KB 以内,同时图片默认展示比例为 5:4,这样小菜默认的图很多是竖直的图,只会展示一部分. 遮挡部分图片 规定 小菜尝试了图片的[等比压缩][非等比压缩]和[不压缩],效果依旧不合适,图片所占位置默认以横向方向填充满分享出的布局

  • Docker 镜像分层及dockerfile 编写技巧

    docker镜像分层 分层介绍 Dockerfile中的每个指令都会创建一个新的镜像层 镜像层将被缓存和复用 当Dockerfile的指令修改了,复制的文件变化了,或者构建镜像时指定的变量不同了,对应的镜像层缓存就会失效 某一层的镜像缓存失效之后,它之后的镜像层缓存都会失效 镜像层是不可变的,如果在某一层中添加一个文件,然后在下一层中删除它,则镜像中依然会包含该文件 Docker镜像原理 Docker镜像是由特殊的文件系统叠加而成 ·最底端是bootfs,并使用宿主机的bootfs ·第二层是r

  • 两个Javascript小tip资料

    1. 定时循环执行代码 复制代码 代码如下: window.setInterval(function() { $.get("service.aspx?method=unreadmessage", function(data) { if (data != "0") $('#unreadCount').html(data).show(); else $('#unreadCount').hide(); }); }, 1000);可以类似这样写. 2. 刷新当前页面 复制代

  • 关于c语言指针的两处小tip分享

    1:常量指针与指针常量 常量指针与指针常量名字很接近,但是两者区别很大. 常量指针是指指向常量的指针,例如:char const *st[4]="str";或者使用下面的方法,效果是一样的:const char *st[4]="str"; 它声明了一个指针变量,这个指针指向了一个常量字符串,但是由于指向的内存空间是常量,因此该地址的内容是不能修改的,例如:*st="no"; //这是不行的,因为内存空间的内容不能修改st="ok&quo

  • PHP小技巧搜集,每个PHPer都来露一手

    这个帖子主要是所有的PHPers把自己在开发或学习中的一些经验技巧进行总结,主要就是把解决某种事情更好的方法告诉大家. 我先说几个: 1,假如你使用echo输出一个简单的语句,类似与: 复制代码 代码如下: <?php  echo "Hello World!";  ?>  那么你可以偷懒一下,写成这样:  <?="Hello World!";?> 2,str_replace()可以使用数组进行替换,比如:  复制代码 代码如下: <? 

  • JAVA中使用双括号来初始化静态常量的小技巧

    这貌似是个不为人知的语言技巧.我看到一般人写Java里初始化静态常量都是 复制代码 代码如下: public static final Map<String, String> DATA = new TreeMap<String, String>(); static{ DATA.put("a", "A"); //blah blah blah} 使用所在类的static块来初始化DATA,其实还有另外一种写法: 复制代码 代码如下: public

随机推荐