Linux命令 Dockerfile


原文链接: Linux命令 Dockerfile

http://www.cnblogs.com/52fhy/p/5638571.html
dockerfile 剖析

ENV ENV 的就是给docker来设置变量的. 基本格式为:

ENV name=jimmy age=18

修改环境变量

ENV PATH=$PATH:/user/bin
而通过 ENV 我们就可以完美的告诉docker 从这里开始,你就不能使用cache,自己的重新来.( 因为,每条指令都会生成layer并且有独立的id,一旦你更改的ENV,那么从该指令开始id都会发生改变,也就匹配不到缓存了 )

ARG 指定构建过程中使用的环境变

添加个人信息LABEL

顾名思义,使用 LABEL 就是给你的image打上独一无二的标签.让别人能够了解,这个Image是属于你的. 又或是,用来提醒你自己,这个image现在处于哪一个版本状态.

设置自己的label

LABEL owner="jimmy" version="0.0.1"

在dockerfile定义了默认变量

ARG user=jimy

在运行时,进行手动替换

docker build --build-arg user=sam -t jimmy/demo .

上面说了ARG和ENV比较类似,不过,里面的区别还是有的. 即, ARG只能用在 docker build 的阶段, 并且不会被保存在 image 中,这就是和ENV的区别.

##############Dockerfile#########################

容器需要开放SSH 22端口

EXPOSE 22
!!!
ENTRYPOINT,表示镜像在初始化时需要执行的命令,不可被重写覆盖,需谨记
CMD,表示镜像运行默认参数,可被重写覆盖
ENTRYPOINT/CMD都只能在文件中存在一次,并且最后一个生效 多个存在,只有最后一个生效,其它无效!
需要初始化运行多个命令,彼此之间可以使用 && 隔开,但最后一个须要为无限运行的命令,需切记!

ENTRYPOINT/CMD,一般两者可以配合使用,比如:

ENTRYPOINT ["/usr/sbin/sshd"]
CMD ["-D"]

在Docker daemon模式下,无论你是使用ENTRYPOINT,还是CMD,最后的命令,一定要是当前进程需要一直运行的,才能够防容器退出。

以下无效方式:

ENTRYPOINT service tomcat7 start #运行几秒钟之后,容器就会退出
CMD service tomcat7 start #运行几秒钟之后,容器就会退出

这样有效:

ENTRYPOINT service tomcat7 start && tail -f /var/lib/tomcat7/logs/catalina.out

或者

CMD service tomcat7 start && tail -f /var/lib/tomcat7/logs/catalina.out

这样也有效:

ENTRYPOINT ["/usr/sbin/sshd"]
CMD ["-D"]

Capabilities的主要思想在于分割root用户的特权,即将root的特权分割成不同的能力,每种能力代表一定的特权操作。例如:能力CAP_SYS_MODULE表示用户能够加载(或卸载)内核模块的特权操作,而CAP_SETUID表示用户能够修改进程用户身份的特权操作。在Capbilities中系统将根据进程拥有的能力来进行特权操作的访问控制。

在Capilities中,只有进程和可执行文件才具有能力,每个进程拥有三组能力集,分别称为cap_effective, cap_inheritable, cap_permitted(分别简记为:pE,pI,pP),其中cap_permitted表示进程所拥有的最大能力集;cap_effective表示进程当前可用的能力集,可以看做是cap_permitted的一个子集;而cap_inheitable则表示进程可以传递给其子进程的能力集。系统根据进程的cap_effective能力集进行访问控制,cap_effective为cap_permitted的子集,进程可以通过取消cap_effective中的某些能力来放弃进程的一些特权。可执行文件也拥有三组能力集,对应于进程的三组能力集,分别称为cap_effective, cap_allowed 和 cap_forced(分别简记为fE,fI,fP),其中,cap_allowed表示程序运行时可从原进程的cap_inheritable中集成的能力集,cap_forced表示运行文件时必须拥有才能完成其服务的能力集;而cap_effective则表示文件开始运行时可以使用的能力。

(一)Linux内核中Capabilities的实现机制

 Linux内核从2.2版本开始,就加进的Capabilities的概念与机制,并随着版本升高逐步得到改进。在linux中,root权限被分割成一下29中能力:

CAP_CHOWN:修改文件属主的权限
CAP_DAC_OVERRIDE:忽略文件的DAC访问限制
CAP_DAC_READ_SEARCH:忽略文件读及目录搜索的DAC访问限制
CAP_FOWNER:忽略文件属主ID必须和进程用户ID相匹配的限制
CAP_FSETID:允许设置文件的setuid位
CAP_KILL:允许对不属于自己的进程发送信号
CAP_SETGID:允许改变进程的组ID
CAP_SETUID:允许改变进程的用户ID
CAP_SETPCAP:允许向其他进程转移能力以及删除其他进程的能力
CAP_LINUX_IMMUTABLE:允许修改文件的IMMUTABLE和APPEND属性标志
CAP_NET_BIND_SERVICE:允许绑定到小于1024的端口
CAP_NET_BROADCAST:允许网络广播和多播访问
CAP_NET_ADMIN:允许执行网络管理任务
CAP_NET_RAW:允许使用原始套接字
CAP_IPC_LOCK:允许锁定共享内存片段
CAP_IPC_OWNER:忽略IPC所有权检查
CAP_SYS_MODULE:允许插入和删除内核模块
CAP_SYS_RAWIO:允许直接访问/devport,/dev/mem,/dev/kmem及原始块设备
CAP_SYS_CHROOT:允许使用chroot()系统调用
CAP_SYS_PTRACE:允许跟踪任何进程
CAP_SYS_PACCT:允许执行进程的BSD式审计
CAP_SYS_ADMIN:允许执行系统管理任务,如加载或卸载文件系统、设置磁盘配额等
CAP_SYS_BOOT:允许重新启动系统
CAP_SYS_NICE:允许提升优先级及设置其他进程的优先级
CAP_SYS_RESOURCE:忽略资源限制
CAP_SYS_TIME:允许改变系统时钟
CAP_SYS_TTY_CONFIG:允许配置TTY设备
CAP_MKNOD:允许使用mknod()系统调用
CAP_LEASE:允许修改文件锁的FL_LEASE标志
################################################################################

docker 搭建Android开发环境

docker pull ubuntu:10.04
docker run -it -p 8080:80 -v /media/ubuntu/sdb2/Android:/mnt -w /mnt ubuntu:10.04 /bin/bash

docker ps -a
docker start 8c055f32bd33
docker attach 8c055f32bd33
sudo vi /etc/apt/source.list
sed -i 's/httpredir.debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list

sudo sed -i 's/archive.ubuntu.com/mirrors.sohu.com/g' /etc/apt/sources.list
sudo sed -i 's/archive.ubuntu.com/mirrors.163.com/g' /etc/apt/sources.list
sudo sed -i 's/archive.ubuntu.com/mirrors.ustc.edu.cn/g' /etc/apt/sources.list
sudo sed -i 's/archive.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list
sudo sed -i 's/archive.ubuntu.com/mirrors.aliyuncs.com/g' /etc/apt/sources.list #内网使用

#网易
deb http://mirrors.163.com/ubuntu/ lucid main universe restricted multiverse
deb-src http://mirrors.163.com/ubuntu/ lucid main universe restricted multiverse
deb http://mirrors.163.com/ubuntu/ lucid-security universe main multiverse restricted
deb-src http://mirrors.163.com/ubuntu/ lucid-security universe main multiverse restricted
deb http://mirrors.163.com/ubuntu/ lucid-updates universe main multiverse restricted
deb http://mirrors.163.com/ubuntu/ lucid-proposed universe main multiverse restricted
deb-src http://mirrors.163.com/ubuntu/ lucid-proposed universe main multiverse restricted
deb http://mirrors.163.com/ubuntu/ lucid-backports universe main multiverse restricted
deb-src http://mirrors.163.com/ubuntu/ lucid-backports universe main multiverse restricted
deb-src http://mirrors.163.com/ubuntu/ lucid-updates universe main multiverse restricted

sudo apt-get update

sudo apt-get install gnupg flex bison gperf build-essential
zip curl zlib1g-dev libc6-dev lib32ncurses5-dev ia32-libs
x11proto-core-dev libx11-dev lib32readline5-dev lib32z-dev
libgl1-mesa-dev g++-multilib mingw32 tofrodos python-markdown
libxml2-utils xsltproc

sudo apt-get install software-properties-common
sudo apt-get install python-software-properties
sudo add-apt-repository ppa:webupd8team/java #添加PPA
sudo apt-get update
sudo apt-get install oracle-java6-installer #java-6u45

sudo docker commit -m="Android source Complie" -a="rinetd" ab044db61af2 rinetd/ubuntu:v1
docker tag 5db5f8471261 rinetd/ubuntu:devel
docker push rinetd/ubuntu

###
Docker命令参考
使用方法: docker [OPTIONS] COMMAND [arg...]

一个自给自足的运行时linux容器。

选项:
--api-enable-cors=false 在远程的API中启用CORS 头。
-b, --bridge="" 附加容器到一个已经存在的网桥上。如果将该选项的值设置为 'none',则表示不使用用网桥。
--bip="" 设置网桥的IP地址,使用CIIDR标记方式的地址,不兼容 -b选项。
-D, --debug=false 启用debug 模式。
-d, --daemon=false 启用daemon 模式。
--dns=[] 强制Docker使用特定的DNS 服务器。
--dns-search=[] 强制 Docker使用特定的DNS 搜索域。
-e, --exec-driver="native" 强制Docker运行时使用特定的exec驱动。
--fixed-cidr="" IPv4子网设置掩码(ex: 10.20.0.0/16),这个子网必须嵌套于网桥子网内(由-b 或者-bip定义)。
-G, --group="docker" 在使用-H运行为守护进程的情况下,设定分配给运行unix套接字的组,如果设置为'' (空字符),那么将不会设置组。
-g, --graph="/var/lib/docker" 设定Docker运行时作为根目录的目录路径。
-H, --host=[] 设置用于在守护进程模式下或者是在客户端模式下连接的套接字,可以是tcp://host:port, unix:///path/to/socket, fd://* or fd://socketfd中的一个或者多。
--icc=true 启用容器间通信。
--insecure-registry=[] 对于特定注册启用非安全通信(对于HTTPS没有证书校验,启用HTTP启用fallback) (例如, localhost:5000 or 10.20.0.0/16)。
--ip=0.0.0.0 在容器绑定端口时使用的默认IP地址。
--ip-forward=true 启用net.ipv4.ip_forward,也就是开启路由转发功能。
--ip-masq=true 对于网桥的IP段启用ip伪装。
--iptables=true 启用Docker增加的iptables规则。
--mtu=0 设置容器网络的MTU。如果没有提供设置的值:默认将它的值设置为路由器的MTU,如果默认的路由器无效那么就设置为1500。
-p, --pidfile="/var/run/docker.pid" 设置守护进程PID文件的路径。
--registry-mirror=[] 指定优先使用的Docker registry镜像。
-s, --storage-driver="" 强制Docker运行时使用特定的存储驱动器。
--selinux-enabled=false 启用对selinux机制的支持。SELinux目前不支持BTRFS存储驱动器。
--storage-opt=[] 设置存储驱动器选项。
--tls=false 使用TLS,暗示使用tls-verify标志。
--tlscacert="/root/.docker/ca.pem" 设置ca证书的路径。远程访问仅信任使用由CA签名的证书。
--tlscert="/root/.docker/cert.pem" 设置TLS 证书的路径。
--tlskey="/root/.docker/key.pem" 设置TLS key 文件的路径。
--tlsverify=false 使用TLS校验远程登录(daemon:校验客户端, client: 校验守护进程)
-v, --version=false 显示版本信息并退出。

命令:
attach 附加到一个运行的容器上。
build 从Dockerfile构建镜像。
commit 从改变后的容器创建一个新的镜像
cp 从容器文件系统拷贝文件/目录到宿主机路径。
create 创建一个新的容器。
diff 检查容器文件系统的改变。
events 从Get real time events from the server
exec 在已经存在的容器上运行一个命令。
export Stream the contents of a container as a tar archive
history 显示镜像的历史。
images 列举镜像。
import 从一个tar包的内容创建一个新的文件系统镜像。
info 显示系统层面的信息。
inspect 查看容器的底层信息。
kill 杀掉一个正在运行中的容器。
load 从tar文件中载入一个镜像。
login 注册或者登录到Docker registry 服务器。
logout 从Docker registry 服务器退出。
logs 获取容器的日志信息。
port Lookup the public-facing port that is NAT-ed to PRIVATE_PORT
pause 停止容器内所有的进程。
ps 列出容器。
pull 从Docker registry 服务器拉回一个镜像或者一个仓库。
push 将一个镜像或者一个仓库推向Docker registry 服务器。
restart 重新启动一个运行中的容器。
rm 移除一个或者多个容器。
rmi 移除一个或者多个镜像。
run 在新的容器中运行一个命令。
save 将镜像保存为一个tar文档。
search 在Docker Hub上搜索一个镜像。
start 启动一个停止的容器。
stop S停止一个运行中的容器。
tag Tag an image into a repository
top 查看容器中运行的进程。
unpause 取消暂停的容器。
version 显示Docker 的版本信息。
wait Block until a container stops, then print its exit code

docker attach

使用方法: docker attach [OPTIONS] CONTAINER

附加到一个正在运行的容器上。

--no-stdin=false 不附加STDIN。
--sig-proxy=true 代理所有接收到的信号到进程(即使是非TTY模式)。SIGCHLD, SIGKILL, 或者 SIGSTOP 不会被代理。

docker build

使用方法: docker build [OPTIONS] PATH | URL | -

在指定的PATH源代码下构建新的镜像。

--force-rm=false 总是立即移除容器,即使是在成功创建之后。
--no-cache=false 在构建镜像时不使用缓存。
-q, --quiet=false 抑制由容器生成详细输出。
--rm=true 成功创建容器之后就立即删除。
-t, --tag="" 指定仓库名字(和一个可选的标签),在构建成功的镜像结果中应用。

docker commit

使用方法: docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]

从有改变的容器上创建一个新的镜像。

-a, --author="" 作者 (例如 "John Hannibal Smith hannibal@a-team.com"
-m, --message="" 提交信息。
-p, --pause=true 在提交的过程中暂停容器。

docker cp

使用方法: docker cp CONTAINERATH HOSTPATH

从PATH 拷贝文件/目录到 HOSTPATH。

docker create
使用方法: docker create [OPTIONS] IMAGE [COMMAND] [ARG...]

创建一个新容器。

-a, --attach=[] 附加到STDIN, STDOUT 或者STDERR。
--add-host=[] 自定义一个主机到IP的映射(host:ip)。
-c, --cpu-shares=0 设定CPU共享(相对权重)。
--cap-add=[] 添加Linux capabilities。
--cap-drop=[] 移除 Linux capabilities。
--cidfile="" 写容器ID的文件。
--cpuset="" 设置使用CPU的数量(0-3, 0,1)。
--device=[] 添加一个主机设备到容器(例如
--device=/dev/sdc:/dev/xvdc)
--dns=[] 设置自定义DNS 服务器。
--dns-search=[] 设置自定义DNS 搜索域。
-e, --env=[] 设置环境变量。
--entrypoint="" 覆盖掉镜像中默认的ENTRYPOINT。
--env-file=[] 读以逗号分隔的环境变量文件(文件中的行以逗号分隔,每一行都是环境变量)。
--expose=[] 将一个没有发布的端口暴露给宿主机。
-h, --hostname="" 容器主机名字。
-i, --interactive=false 保持 STDIN 打开,即使没有被附加。
--link=[] 以name:alias格式添加连接到其它容器上。
--lxc-conf=[] (lxc exec-driver only) 添加自定义lxc 选项
--lxc-conf="lxc.cgroup.cpuset.cpus = 0,1"
-m, --memory="" 内存限制 (格式: ,
unit = b, k, m or g)
--name="" 指定容器的名字。
--net="bridge" 为容器设置网络模式,

                           'bridge': 在docker bridge桥上创建一个新的网络栈。
                             'none': 该容器没有网络。
              'container:<name|id>': 重新使用其它容器的网络栈。
                             'host': 在该容器内使用host网络堆栈。注意:host模式对宿主机上的本地文件系统给定了容器全部的访问权限,包括D-bus,因此容器被认为是不安全的。

-P, --publish-all=false 发布所有的暴露端口到宿主机接口上。
-p, --publish=[] 发布容器的一个端口到宿主机接口上。

                         格式:

ip:hostPort:containerPort
ip::containerPort
hostPort:containerPort
containerPort

                           (使用 'docker port'查看实际的映射)

--privileged=false 给这个容器扩展权限。
--restart="" 当容器退出时重启策略将会被应用,选项值有:
(no, on-failure[:max-retry], always)
--security-opt=[] 安全选项。
-t, --tty=false 分配伪终端。
-u, --user="" 用户名或者UID。
-v, --volume=[] 绑定挂载卷(例如,从宿主机挂接:-v /host:/container,从Docker挂接:-v /container)
--volumes-from=[] 从指定的容器挂载卷。
-w, --workdir="" 指定容器内的工作目录。

docker diff

使用方法: docker diff CONTAINER

查看容器内文件系统的变化。

docker events

使用方法: docker events [OPTIONS]

从服务器上获得实时事件。
--since="" 从指定的时间戳后显示所有事件。
--until="" 流水时间显示到指定的时间为止。

docker exec

使用方法: docker exec [OPTIONS] CONTAINER COMMAND [ARG...]

在已经存在的容器内运行一个命令。

-d, --detach=false 分离模式: 在后台运行
-i, --interactive=false 即使没有附加也保持STDIN 打开
-t, --tty=false 分配一个伪终端

docker export

使用方法: docker export CONTAINER

将文件系统作为一个tar归档文件导出到STDOUT。

docker info

使用方法: docker info

显示系统级别的信息。

docker history

使用方法: docker history [OPTIONS] IMAGE

显示镜像的历史。

--no-trunc=false 不要截断输出。
-q, --quiet=false 只显示数字ID。

docker images

使用方法: docker images [OPTIONS] [NAME]

列出镜像。

-a, --all=false 显示所有镜像(默认情况下过滤掉中间层镜像)。
-f, --filter=[] 提供过滤值 (例如. 'dangling=true')
--no-trunc=false 不要截断输出。
-q, --quiet=false 只显示数字ID。

docker import

使用方法: docker import URL|- [REPOSITORY[:TAG]]

创建一个空的文件系统镜像,并且将压缩包(.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz)内容输入到其中。

docker inspect

使用方法: docker inspect [OPTIONS] CONTAINER|IMAGE [CONTAINER|IMAGE...]

查看容器或者镜像的低级信息。

-f, --format="" 使用给定的模板格式化输出。

docker kill

使用方法: docker kill [OPTIONS] CONTAINER [CONTAINER...]

使用SIGKILL杀掉指定的容器。

-s, --signal="KILL" 向容器发送的信号。

docker load

使用方法: docker load [OPTIONS]

从STDIN上载入tar包作为镜像。

-i, --input="" 从tar文件,而不是STDIN读取。

docker login

使用方法: docker login [OPTIONS] [SERVER]

注册或者登录到一个Docker服务器,如果没有指定服务器,那么https://index.docker.io/v1/将会作为默认值。

-e, --email="" 邮件
-p, --password="" 密码
-u, --username="" 用户名

docker logout

使用方法: docker logout [SERVER]

从一个Docker registry退出,如果没有指定服务器,那么https://index.docker.io/v1/将会作为默认值。

docker logs

使用方法: docker logs [OPTIONS] CONTAINER

从容器获取日志。

-f, --follow=false 跟踪日志输出。
-t, --timestamps=false 显示时间戳。
--tail="all" 输出日志尾部特定行(默认是所有)。
docker port

使用方法: docker port CONTAINER [PRIVATE_PORT[/PROTO]]

列出指定的容器的端口映射,或者查找将PRIVATE_PORT NAT到面向公众的端口。

docker pause
使用方法: docker pause CONTAINER

暂停容器内所有的进程。

docker ps

使用方法: docker ps [OPTIONS]

列出容器。

-a, --all=false 显示所有的容器。默认情况下仅显示正在运行的容器。
--before="" 仅显示在ID或者名字之前的容器,包括没有运行的容器。
-f, --filter=[] 提供过滤值. 有效的过滤器:

                      exited=<int> - 容器退出的代码 <int>
                      status=(restarting|running|paused|exited)

-l, --latest=false 仅显示最后一个创建的容器,包括没有运行的。
-n=-1 显示n个最后创建的容器,包括没有运行的。
--no-trunc=false 不要截断输出。
-q, --quiet=false 仅显示数值ID。
-s, --size=false 显示大小。
--since="" 仅显示从Id 或者 Name以来的容器,包括没有运行的。

docker pull

使用方法: docker pull [OPTIONS] NAME[:TAG]

从registry上拉回一个镜像或者一个容器。

-a, --all-tags=false 在指定的仓库下载所有标记的镜像。

docker push

使用方法: docker push NAME[:TAG]

将一个镜像或者仓库推送到指定的仓库。

docker restart

使用方法: docker restart [OPTIONS] CONTAINER [CONTAINER...]

重新启动一个运行中的容器。

-t, --time=10 在杀掉指定容器之前停动的时间,一旦杀掉容器,那么就会重新启动。默认时间为10秒。

docker rm

使用方法: docker rm [OPTIONS] CONTAINER [CONTAINER...]

删除一个或者多个容器。

-f, --force=false 强制移除一个正在运行的容器(使用 SIGKILL)
-l, --link=false 移除指定的连接,而不是潜在的容器。
-v, --volumes=false 移除与容器相关的卷。

docker rmi

使用方法: docker rmi [OPTIONS] IMAGE [IMAGE...]

移除一个或者多个镜像。

-f, --force=false 强制移除一个镜像。
--no-prune=false 不要删除未标记的父镜像。

docker run

使用方法: docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

在新的容器中运行一个命令。

-a, --attach=[] 附加到STDIN, STDOUT 或者 STDERR。
--add-host=[] 添加一个自定义的host-to-IP 映射(host:ip)。
-c, --cpu-shares=0 CPU shares (相对权重)。
--cap-add=[] 添加Linux capabilities。
--cap-drop=[] 放弃 Linux capabilities。
--cidfile="" 将容器 ID写入文件。
--cpuset="" 允许使用的CPU数量(0-3, 0,1)
-d, --detach=false 分离模式:在后台运行容器,并且显示出新容器的ID。
--device=[] 向容器添加一个宿主机设备。
(例如, --device=/dev/sdc:/dev/xvdc)
--dns=[] 设置自定义的DNS 服务器。
--dns-search=[] 设置自定义DNS 搜索域。
-e, --env=[] 设置环境变量。
--entrypoint="" 覆盖掉镜像中默认的ENTRYPOINT。
--env-file=[] 读以逗号分隔的环境变量文件(文件中的行以逗号分隔,每一行都是环境变量)。
--expose=[] 将一个没有发布的端口暴露给宿主机。
-h, --hostname="" 容器主机名字。
-i, --interactive=false 保持 STDIN 打开,即使没有被附加。
--link=[] 以name:alias格式添加连接到其它容器上。
--lxc-conf=[] (lxc exec-driver only) 添加自定义lxc 选项
--lxc-conf="lxc.cgroup.cpuset.cpus = 0,1"
-m, --memory="" 内存限制 (格式: ,
unit = b, k, m or g)
--name="" 指定容器的名字。
--net="bridge" 为容器设置网络模式,

                           'bridge': 在docker bridge桥上创建一个新的网络栈。
                             'none': 该容器没有网络。
              'container:<name|id>': 重新使用其它容器的网络栈。
                             'host': 在该容器内使用host网络堆栈。注意:host模式对宿主机上的本地文件系统给定了容器全部的访问权限,包括D-bus,因此容器被认为是不安全的。

-P, --publish-all=false 发布所有的暴露端口到宿主机接口上。
-p, --publish=[] 发布容器的一个端口到宿主机接口上。

                         格式:

ip:hostPort:containerPort
ip::containerPort
hostPort:containerPort
containerPort

                           (使用 'docker port'查看实际的映射)

--privileged=false 给这个容器扩展权限。
--restart="" 当容器退出时重启策略将会被应用,选项值有:
(no, on-failure[:max-retry], always)
--security-opt=[] 安全选项。
-t, --tty=false 分配伪终端。
-u, --user="" 用户名或者UID。
-v, --volume=[] 绑定挂载卷(例如,从宿主机挂接:-v /host:/container,从Docker挂接:-v /container)
--volumes-from=[] 从指定的容器挂载卷。
-w, --workdir="" 指定容器内的工作目录。

docker save

使用方法: docker save [OPTIONS] IMAGE [IMAGE...]

将镜像保存到一个归档文件(默认为STDOUT)

-o, --output="" 输出到一个文件而不是STDOUT。

docker search

使用方法: docker search [OPTIONS] TERM

从Docker Hub 上搜索镜像。

--automated=false 仅显示自动构建。
--no-trunc=false 不要截断输出。
-s, --stars=0 仅显示至少x 星级的镜像。

docker start

使用方法: docker start [OPTIONS] CONTAINER [CONTAINER...]

重新启动一个停止的容器。

-a, --attach=false 附加容器的STDOUT 和 STDERR,并且所有的信号到进程。
-i, --interactive=false 附加容器的STDIN。

docker stop

使用方法: docker stop [OPTIONS] CONTAINER [CONTAINER...]

通过发送SIGTERM 信号,在一个优雅的时间断后然后是SIGKILL停止运行的容器。

-t, --time=10 在杀掉容器之前等待容器停止的时间数。

docker tag

使用方法: docker tag [OPTIONS] IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]

标记一个进入仓库的镜像。

-f, --force=false 强制。

docker top

使用方法: docker top CONTAINER [ps OPTIONS]

显示容器中运行的进程。

docker unpause
使用方法: docker unpause CONTAINER

取消暂停容器内的所有进程。

docker version

使用方法: docker version

显示Docker的版本信息。

docker wait

使用方法: docker wait CONTAINER [CONTAINER...]

Block until a container stops, then print its exit code.
阻塞运行直到容器停止,然后打印出它的退出代码。

##############################################################################
docker 之所以这么牛逼, 一是在于他强大的生态环境, 以及,他container和writable layer 的新颖的概念.
docker镜像的简单剖析

docker的images,我们可以理解为积木, 一层一层往上搭, 最后完成一个工程化的大项目.

在最初,docker实际上,只有一个静态的image(Ps: read-only). 相当于只能读, 所以, 你所有的改动并不会影响到原来的image上, 只会一层一层的叠加, 比如, 你在Ubuntu的image上面, 再接一层nodeJS的image. 实际上的结果是, 两个image叠加起来.

这里放一张 the Docker book 的说明图:

(Ps: 算啦,估计大家也没听懂,还是在下面根据实例,来进行细致的区分吧)

docker 在下载image的时候,会在 /var/lib/docker 目录下创建相关的image 目录. 而运行的container则会放在 /var/lib/docker/containers 中.

另外,docker中的image,是存储在 docker仓库 . 现在,我们通过快速创建自已的仓库来仔细了解一下docker是怎样拥有这样一个完善的生态的.
docker 仓库

首先, 要想拥有自己的docker 仓库, 你得有一个自己的docker账号.so, 那就想apply 一个呗. 在 docker hub 上面注册一下自己的账号就行.
登录指令

在docker中,不仅支持web查看docker中的内容, 而且还支持使用命令行登录.

// 登录到docker
docker login // 然后输入账户密码就ok了
// 使用完毕,想要登出
docker logout

实际上,docker会将你的认证信息存放在. ~/.docker/config.json 当中。
images 常用命令

如果浏览了上面的docker仓库, 会发现在一个repository里面会存在很多images, 比如 ubuntu的repository .不同的images发布,代表的都是特定的版本系统. 所以,在拉取的时候,需要额外注意一下你需要的指定docker images.
images的拉取

在container中,我们讲过,使用docker run的时候, 你会发现如果你的images里面没有存在指定的image时, docker会主动去docker hub里面找,然后下载,并且自动运行.

// 运行最新版的ubuntu image
docker run -t -i ubuntu:latest

如果,你想自己手动下载images的话,可以直接 pull

// 手动拉取images
docker pull ubuntu:latest
// 拉取12.04版本的ubuntu images
docker pull ubuntu:12.04

如果在拉取的时候,想知道这个image是否是真正存在的话,就可以使用.docker 提供的搜索指令.
搜索指定docker

在docker中,可以使用自带的 search 命令,搜索所有含有指定term的image. 相当于js中的search 方法.

// 搜索name中含有demo的image
docker search demo
// 结果为: 名字. 通常为: author/image_name . 通常搜索的就是这个
// 描述: 就是一段文字描述
NAME DESCRIPTION STARS OFFICIAL AUTOMATED

查到之后,我们就可以使用pull将指定的库,拉下来了.
创建自己的image

上面说过, contianer是copy image运行的进程容器,image是不会变的read-only 块. 但是,如果我们在container里面, 改动了一些设置,比如,下载了node, 而且,我想要保存我这次改动, 以至于,下次我想重新,启动该image时, 他已经具备了node.

// 现在我再ubuntu:latest上面安装了node
// 伪代码
npm install node -g

docker提供了一个非常快捷的方式就是创建自己的docker image. 使用 docker commit .

// 查看刚才改动的container ID
docker ps -a -q -l
// 得到 docker_id, 提交到自己的库中
docker commit docker_id villainHR/node
// 之后会返回新的image id

需要注意, docker commit 提交的并不是一个整体的100+MB的ubuntu+node. 他只会将两个仓库的差异提交,比如原来image和新的image比起来,就是多了一个 npm install node -g 命令.
使用Dockerfile

Dockerfile是为了迅速的构建image而出现的. 他与docker commit 的区别在于. 能够迅速的更替历史image 命令. 比如,我们以前下载的npm是version 2, 现在想要更换为npm@3的话,则难度就不是一般的了. 但是,如果我们能够像写命令一样将下载的配置命令下载Dockerfile里面, 那么以后我们想要更换版本,就是很方便的啦.

ok, 现在我们来了解一下Dockerfile是怎样的运行的.
dockerfile demo讲解

这里,我们利用dockerfile 来搭建一个简单的webServer. 首先创建一个你自己的dockerfile目录

mkdir first_docker
cd first_docker
touch Dockerfile

然后, 确保你有ubuntu:latest image.因为, 接下来我们就是基于它,来搭建我们的server.

first dockerfile demo

FROM ubuntu:latest

设置该dockerfile的作者和联系邮箱

MAINTAINER Jimmy "villainhr@gmail.com"

开始配置环境, 下载apt-get,生成index.html的文件

RUN apt-get update && apt-get install -y nginx
RUN echo 'first demo' > /usr/share/nginx/html/index.html

暴露server的port

EXPOSE 80

说一下上面的命令内涵.

FROM: 用来指定第一层image, 这是必须有的. 并且指定的image是存在在你的computer中. 相当于是 docker run.

RUN: 这是用来在container中,做出相应的修改. 相当于 修改+docker commit xxx . 给原来的image加上一层layer. 然后, docker会在你commit新一层之后,重新docker run你最新改动过的image

MAINTAINER: 设置作者和联系邮箱.其实就是docker commit 后面的Name参数. 而且加上了联系邮箱. 这是在dockerfile 运行完后,会自动添加到image上的.

EXPOSE: 用来给最新的container 设置与外部交流的port

上面简单的介绍了基本的dockerfile的命令. 不过, 这尼玛太简单了,不符合我们一贯追求到底的风格.

这里, 我们在来细说一下RUN这个命令. 实际上, 这应该是dockerfile的关键. RUN的原理很简单, 就是 commit + run . 先创建一个新的image 然后 在这个基础上将原有的container替换为新的,如果某一步的RUN发生错误,则container会停在那个阶段, 这样,你可以直接进入该container去查看,你那一步的RUN发生了什么BUG。 另外, 使用RUN的时候, 需要注意, 由于,dockerfile是由上到下解析的, 比如你一开始 FROM ubuntu 的image, 那么此时的环境是停留在ubuntu的shell中的.

比如:

RUN touch demo.js
// 等同于
/bin/sh -c touch demo.js

所以, 如果你调用的image 并没有shell的话, 那么久需要使用exec调用系统shell 来执行命令.

// 调用系统的shell来运行, 实际上就是 exec xxx xxx xxx.
RUN ["npm","install","node"]

运行dockerfile

上面的dockerfile文件配置好了之后,就轮到我们运行dockerfile.直接运行 docker build 即可.

// 注意后面的".", 用来指定搜索dockerfile文件的路径.
docker build -t="jimmy/first_dockerfile" .

说一下docker build的指令吧.

// 基本格式为:
docker build -t="repository/name:tag" directory
// -t用来指定生成的image的name,比如仓库,image的名字以及他的tag,如果你不指定tag, 那么docker会自动添加latest代替。
// directory 用来相对于当前运行build的目录, 搜索指定的dockerfile.当然,你也可以使用绝对路径了

顺利的话,应该就会有, 下列的信息出来.

Sending build context to Docker daemon 2.048 kB
Step 1 : FROM ubuntu:latest
---> c5f1cf30c96b
Step 2 : MAINTAINER jimmy "villainhr@gmai.com"
---> Running in 078148a5086a
---> 11b061f665d1
Removing intermediate container 078148a5086a
Step 3 : RUN cd /var
---> Running in ffd3141e64c8
---> a4d7c5303b60
Removing intermediate container ffd3141e64c8
Step 4 : RUN touch demo.js
---> Running in c8393a6fcc98
---> 109b402b9adc
Removing intermediate container c8393a6fcc98
Step 5 : EXPOSE 80
---> Running in 2c064f4bac57
---> ff7ad58a5d8a
Removing intermediate container 2c064f4bac57
Successfully built ff7ad58a5d8a

然后, 你可以使用 docker images 查看.就会发现多出来一个image.
dockerfile cache

上面已经提到过,使用docker build的时候,如果你的dockerfile中的某一步出现问题的话,你生成的image会停留在那一步.当你fix errors时, 重新运行 docker build , 此时,docker是不会真的重头来建一遍的,他会使用你改动line的前一个image,然后以此为基点继续向下构建.

不过,如果你使用缓存的话,他前面的版本id是不会发生改变的.如果你想完整的得到一个新的ID的话,就可以在build的时候,禁用掉cache.

docker build --no-cache -t="jimmy/first_dockerfile" .

不过,该方法是不推荐的. 因为一个非常棒的cache机制,就被你硬生生的cancel. 而且,这也极力不推荐使用该方法进行cache的取消.以为,有些地方,我们完全可以利用cache来加快速度.这就需要使用到 ENV 关键字.来帮助我们,另外利用cache.

在讲解 ENV 之前,先给大家讲解一下docker cache的运行机理.

(是不是感觉很激动~)

实际上,机理就一句话: ID命中 . 因为docker在你每次运行一行命令的时候,会自动生成一个id值.

Sending build context to Docker daemon 2.048 kB
Step 1 : FROM ubuntu:latest
---> c5f1cf30c96b // 这就是ID值

docker借由这个ID值,来判断是否有cache镜像.所以,这里就需要借一下 ENV 这个比较费的指令,来灵活的帮助我们使用cache.
配置化cache

ENV 的就是给docker来设置变量的. 基本格式为:

一个一个的赋值

ENV key value
// demo:
ENV name jimmy
ENV age 18

另外,还可以一起赋值

ENV key=value[...]
// demo:
ENV name=jimmy age=18

而通过 ENV 我们就可以完美的告诉docker 从这里开始,你就不能使用cache,自己的重新来.( 因为,每条指令都会生成layer并且有独立的id,一旦你更改的ENV,那么从该指令开始id都会发生改变,也就匹配不到缓存了 )

看个demo:

第一个dockerfile

FROM ubuntu:latest
MAINTAINER jimmy "villainhr@gmai.com"
ENV REFRESH first # 这里设置的是refresh=first
RUN cd /var
RUN touch demo.js
EXPOSE 80

// 使用docker build ... 后面就会生成一系列新的id和images
// 现在修改dockerfile

第二个dockerfile

FROM ubuntu:latest
MAINTAINER jimmy "villainhr@gmai.com"
ENV REFRESH second # 这里设置的是refresh=second
RUN cd /var
RUN touch demo.js
EXPOSE 80

// 开始运行docker build... 你会发现,从下面语句开始.
ENV REFRESH second
// 其docker id就已经发生了改变,并且docker 没有了use cache的提示.说明,下面就没有命中缓存了. 所以,如果你想在某一段不使用缓存,只需要将ENV后面的value改变即可.

创建完后, 我们可以使用 docker history ,查看一下刚才创建的image的整个流程.

// 查看image创建的过程
docker history jimmy/first_dockerfile
// 输出的结果为:
2322ddc85cc3 10 hours ago /bin/sh -c #(nop) EXPOSE 80/tcp 0 B
b39397abc7aa 10 hours ago /bin/sh -c touch demo.js 0 B
3c9a4daf4c42 10 hours ago /bin/sh -c cd /var 0 B
b1c2f890a262 10 hours ago /bin/sh -c #(nop) ENV REFRESH=second 0 B
2cf0ee3c373c 10 hours ago /bin/sh -c #(nop) MAINTAINER jimmy "villainhr 0 B

俺的目的,其实是想让你们看看,docker在每一层是怎么执行的-- /bin/sh . 了解了之后,我们就继续了.
docker container的接口暴露

上面通过dockerfile 已经暴露了一个80接口,用来和外部通信。 不过,如果我们没有使用 EXPOSE 暴露接口的话, 那应该怎么做呢?

我们可以直接在外部运行docker image, 手动指定暴露的端口.

同样,暴露80端口给外部交互

docker run -d -p 80 --name demo jimmy/node
node -jimmy app.js

-d是daemon的意思

-p 80 表示暴露80的port给外部

node -jimmy app.js 表示在jimmy/node image里面运行的指令

这里, 我们需要额外了解一下80端口的开启. docker 其实是在底层上面,虚拟化了存储. 并且,docker在运行的时候,会自动向主机要一个ip(假的), 相当于,有了自己的host. (这不就一个主机吗?)

这里我们开启的80端口,是docker在内部虚拟开启的, 他会从32768 到 61000端口之间,随机抽一个映射到docker开启的80端口上, 依此来和外部进行真正的交互(膜拜///).

使用docker ps -l 来查看开启情况

docker ps -l

得到: 只截取了一部分.

0.0.0.0:49154->80 tcp

或者指定查看docker端口开启情况

docker port c96f2c18bb64 80 // ID也可以使用name代替

返回:

0.0.0.0:49154

手动指定端口

如果你不想让docker决定的绑定的接口是哪一个,ok, 你可以自己指定.

手动指定端口

指定docker的8080连接到container暴露的80端口

docker run -d -p 8080:80 --name demo jimmy/node
node -jimmy app.js

甚至你也可以指定ip+port

指定docker的127.0.0.1:8080连接container的80

docker run -d -p 127.0.0.1:8080:80 --name demo jimmy/node
node -jimmy app.js

利用EXPOSE

在写dockerfile的时候,我们已经了解了,使用EXPOSE可以完美的实现端口的暴露. 但如果,我们在dockerfile里面暴露多个port的话,那么-p的参数,感觉有点鸡肋啊喂~

不过,现在我们可以使用 -P (注意是大写). 来手动开启所有在dockerfile中,通过 EXPOSE 暴露的端口.

docker run -d -P --name demo jimmy/node
node -jimmy app.js

外部访问

通过端口开启之后,我们就可以间接的访问docker的路由, 来访问在docker里面开启的端口了.

假如上面我们通过dockre暴露的端口是34251的话,就可以在docker环境外访问了.

ping localhost:34251

dockerfile常用指令
自动化运行CMD

你是不是已经厌烦了使用docker run 来运行命令了呢? 你是不是已经讨厌重复的copy命令运行了呢?

那么请使用 CMD 吧.

CMD的作用是,用来指定当你调其对应的container时, 运行的命令.

比如在dockerfile中,指定/bin/bash.

当调起container时,运行/bin/bash

docker run -t -i jimmy/ubuntu:latest /bin/bash

等同于在dockerfile中指定CMD

CMD ["/bin/bash"]
// 运行docker run
docker run -t -i jimmy/ubuntu:latest

不过,如果你在run后面手动指定指令运行的话,会默认覆盖掉CMD提供的命令.

熟悉了CMD,感觉有种 RUN 的感觉. 但,这两者的区别还是很大的

RUN: 一般是用来给image增加layer来完善image, 他一旦执行完,就和后面的运行没有关系了

CMD: 这个在docker build过程中,是没有半毛钱关系的. 他只和在调用image时,关系比较大

强制运行ENTRYPOINT

这里的 ENTRYPOINT 和 CMD 很相似. 可以说,在一定程度上两者可以互相替代,但,两者的实际意义相差还是挺大的.

ENTRYPOINT 的主要功能是强制执行的环境.

指定ENTRYPOINT为/bin/sh

ENTRYPOINT ["/bin/sh"]
// 然后在build之后,调起container

我们尝试在run后面加上参数:

docker run -t -i jimmy/demo /bin/bash/
// 不出意外的话,会得到一个bug提示:

/bin/sh: 0: Can't open /bin/bash/

所以, ENTRYPOINT 的主要功能实际上是,指定了内部运行命令的解析器. 而使用docker run添加的命令,会被当做参数添加给 ENTRYPOINT .

已经指定了ENTRYPOINT ["/bin/sh"]

运行docker run

docker run -t -i jimmy/demo /bin/bash/

实际上相当于(不出错才怪嘞...)

/bin/sh /bin/bash/

另外,我们还可以使用 CMD 配合 ENTRYPOINT 写成默认参数的效果.

默认执行 /bin/bash default.sh

ENTRYPOINT ["/bin/bash"]
CMD ["default.sh"]

如果你在docker run中指定了参数的话,则CMD会默认被代替

docker run jimmy/demo sam.sh

不过,CMD和ENTRYPOINT都只能在dockerfile里面出现一次.
指定运行目录WORKDIR

既然,我们能够在dockerfile里面运行指定的命令。 但,有时,我们仅仅是想在不同的目录中执行不同的命令. 那,在dockerfile中,如何做到灵活的目录切换呢?

那就得使用docker提供的 WORKDIR 命令了.

在/var/data里面创建data.js

WORKDIR /var/data
RUN touch data.js

然后在/etc 下创建data.conf文件

WORKDIR /etc
RUN touch data.conf

并且当你在使用docker run时,他也会停留在使用 WORKDIR 指定的目录中.
环境变量的设置ENV

ENV 在dockerfile里面的用处,应该算是灰常大的. 什么灵活更新,什么变量设置,什么更改全局变量等. 都是so easy.

那 ENV 到底是用来干嘛的?

答: 就是用来设置变量的啊喂. 只是他是设置全局变量.

比如像PATH神马的之类的.

设置一个DATA的全局变量.

ENV DATA=jimmy

ENV最独特之处在于,他所设置的变量,会在你运行的时候生效.即,如果你修改了PATH,他也会在container中立即生效.

修改环境变量

ENV PATH=$PATH:/user/bin
// 现在进入到运行的container中
echo $PATH

/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/data

挂载通用盘VOLUME

在说里面正式的内容之前,我们先来说一下,什么叫做 VOLUME . 说人话吧, VOLUME 叫做数据卷, 相当于通用盘一样的东西. 他其实也是一个存储装置,我们就把他叫做硬盘吧. 这个硬盘不普通,有>1的外接口.(说人话) 每一个外接口,都可以接入到一个操作系统里面. 即,实现了多个系统的数据共享.

一句话:

VOLUME就是一个数据共享盘

而,docker秉承着,虚拟储存idea, 想下面idea践行到底.

wirte once, run anywhere

(感觉,在哪见过)

所以, dockerfile提供了一个 VOLUME 的指令,能够让我们指定数据卷的位置.

指定/opt/data为数据卷

VOLUME ["/opt/data"]

指定多个目录为数据卷/opt/data, /opt/project

VOLUME ["/opt/data","/opt/project"]

当然,关于数据卷的操作,肯定不止挂载这一点,还有迁移,备份等等,相关操作. 具体,可以参考: Docker VOLUME
添加外部文件ADD

有时,我们仅仅是想将外部文件copy到container中,docker有办法吗?

nonsense

docker 提供了 ADD 命令,来帮助我们完成文件的添加. 不过,这里ADD有点限制, 即, 你添加的文件或者目录,只能在docker build运行的目录下, 因为,这是docker在调起container的时候,只将该目录放进了daemon(尴尬~)

现假设,docker build运行的目录为: /data

// 只能添加指定目录下
// 将/data/sam.js 添加到image中的/opt/node/sam.js
// 如果存在该文件,则不会被覆盖
ADD sam.js /opt/node/

添加文件,还可以使用通配符

// 将所有的js文件,添加到node目录下
ADD *.js /opt/node/

如果destination不是绝对路径,则相对于最近的WORKDIR

// 如果最近的WORKDIR为/var
// 则下列添加的路径为/var/opt/node
ADD *.js opt/node/

当文件被添加到指定目录中时,该文件的权限是755,并且UID和GID都是0.

ADD 还支持url添加,以及文件自动解压.

使用url添加

// 将指定路由的文件放到根目录当中
ADD http://example.com/foobar /

自动解压tar.gz文件

// 将文件解压过后放在指定目录中
ADD latest.tar.gz /var/www/wordpress/

纯粹的COPY

COPY和ADD非常类似. 我们可以做个类比:

ADD 包含 COPY

COPY做的事情比不上ADD, 他比ADD少了解压缩和URL下载的功能. 不过,他耗费的性能比较少,他只做纯粹的添加和下载.他的结构和ADD一毛一样. 不过, 有一点,COPY的时候,如果遇到目录不存在的情况下,COPY会自动创建

COPY file.js /opt/data/

添加个人信息LABEL

顾名思义,使用 LABEL 就是给你的image打上独一无二的标签.让别人能够了解,这个Image是属于你的. 又或是,用来提醒你自己,这个image现在处于哪一个版本状态.

设置自己的label

LABEL owner="jimmy" version="0.0.1"

在创建完image之后, 我们可以使用 docker inspect 来查看我们已经打的LABEL

docker inspect jimmy/node
...
labels:{

owner:"jimmy",
version:"0.0.1"

}
...

本人觉得, 这个指令其实真的,有时, 母鸡用到什么地方去...

并且,书写的时候,最好多个连着写,因为这样只会增加一层image.(image的层数是有限制的)
参数形式ARG

这是docker提供的另外一个,让我有点懵逼的命令. 他的实际效果和 ENV 的区别可以趋近于无。

使用ARG定义变量

ARG buildno

设置默认值

ARG user1=someuser

当然,我们可以在命令中,手动指定替换.

在dockerfile定义了默认变量

ARG user=jimy

在运行时,进行手动替换

docker build --build-arg user=sam -t jimmy/demo .

上面说了ARG和ENV比较类似,不过,里面的区别还是有的. 即, ARG只能用在 docker build 的阶段, 并且不会被保存在 image 中,这就是和ENV的区别.
模板image之ONBUILD

因为dockerfile的构建的层数有限制,所以,这也带给了我们一些麻烦, 如果搭建的环境过多,则会造成写到一半,发现dockerfile已经full. 这时候, 就轮到ONBUILD出场了. ONBUILD 的作用在于,他可以完美的实现模板image的搭建.

ONBUILD的主要作用在于,他定义的命令,可以在子dockerfile中使用.(md... 好绕口)

使用ONBUILD 默认下载Apache

ONBUILD RUN apt-get update && apt-get install -y apache2

// 然后运行docker file 会得到下列结果
Step 3 : ONBUILD RUN apt-get update && apt-get install -y apache2
---> Running in 0e117f6ea4ba
---> a79983575b8

//然后生成一个新的image,我们这里暂且叫他jimmy/demo

接下来,我们再来写一个dockerfile

这里继承上面的jimmy/demo

FROM jimmy/demo:latest
ENV SEX=001

// 运行上面的dockerfile,得到:
Step 0 : FROM jimmy/demo

Executing 1 build triggers

Step onbuild-0 : ADD . /var/www/
---> 1a018213a59d
---> 1a018213a59d
Step 1: ENV SEX=001
...

细心的童鞋可以发现这一条命令:

Step onbuild-0 : RUN apt-get update && apt-get install -y apache2
---> 1a018213a59d
---> 1a018213a59d

他居然在这里自动运行了. 所以,我们可以将 ONBUILD 命令理解为模板命令. 即,子dockerfile里面运行时同样生效(这里,我没有说grandchildren的事).

但 ONBUILD 只能往下延伸一级. 相当于你用 ONBUILD 定义的命令,有两次有效次数,一次在build原来Image时,已经用掉了. 所以, 另外一次(在子dockerfile中使用)用掉了之后就无效了. grandchildren dockerfile就没法使用了.

`