首页 > 代码库 > docker入门篇

docker入门篇

基础知识不回顾了,直接上。

docker的安装与启动

yum remove docker -y

yum install docker-io -y # 需要先配置好epel

 

/etc/init.d/docker start

chkconfig docker on

 

获取镜像

docker pull centos       # docker仓库下载一个镜像例如:docker pull centos:6.7

docker images            #列出本地已存在的镜像

docker images centos # 查看指定的镜像


运行

# docker run centos /bin/echo‘Hello world‘

 

# docker run -i -t centos:6.7/bin/bash

    -i表示输入终端保持打开状态

    -t表示开一个伪终端,并绑定到标准输入上

    -c限制运行的某个容器的CPU配额【最大默认是1024

    --cpuset-cpus=  设置可以绑定使用几个CPU,具体可以看help

    -d 表示后台运行容器,只输出容器的ID到屏幕

    -P表示--publish-all=false     Publish all exposed ports to random ports

    --hostname=docker1.demo.com 表示修改容器的hsotname

    --name=lnmp1      表示给启动的容器命名,不用随机名称

    --dns=xx.xx.xx.xx 自定义DNS服务器地址【不指定该参数的话,就是要外部主机的/etc/resolv.conf来配置容器】

    --add-host "www.demo.com:192.168.2.2"  在容器的/etc/hosts添加一条指定的DNS解析记录

    --expose80 --expose 8080       # 暴露端口在外部Expose a port or a range of ports

    --memory1G       限制容器最大使用的内存

    *centos后面如果不指定版本,则默认选择latest版本

输入exit或者Ctrl+d退出

 

# docker run -ti --name test3--hostname=docker1.demo.com --dns=192.168.2.2 --dns=8.8.8.8 lanmp:v1 /bin/bash  # 复杂的写法

 

# docker run -d ubuntu:14.04/bin/sh -c "while true; do echo hello world; sleep 1; done" 以后台进程模式运行

# docker logs 后面跟容器的NAMES

 

当利用 docker run 来创建容器时,Docker 在后台运行的标准操作包括:

    检查本地是否存在指定的镜像,不存在就从公有仓库下载

    利用镜像创建并启动一个容器

    分配一个文件系统,并在只读的镜像层外面挂载一层可读写层

    从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去

    从地址池配置一个 ip 地址给容器

    执行用户指定的应用程序

    执行完毕后容器被终止

 

# docker ps 查看在运行中的docker实例进程

# docker logs insane_babbage    查看容器中的标准输出

# docker stop insane_babbage    停止某个容器

# docker ps可以看到刚才启动的那个centos容器没有了

# docker ps -a 可以看到所有的容器(包括已停止的)

# docker start insane_babbage      # 如果加-i参数可以进入交互式的容器

# docker version     查看docker客户端版本和进程的版本信息


ubuntu容器安装软件:

默认安装好的ubuntu docker是没有vimping这些命令的。

进入容器后,执行

# apt-get update

# apt-get install vim -y

然后vi /etc/apt/sources.list 添加阿里云的源地址。

# apt-get install inetutils-ping-y

# ping www.qq.com 即可


查看帮助信息

# docker  只输入docker指令,系统会自动列出全部可用的命令列表

# docker images --help

 


创建镜像方法1:修改镜像

# docker run -i -t centos:6.7/bin/bash       记下容器的ID,例如:e2d6c890682f

在容器中添加LAMP环境

# yum install httpd mysql mysql-server php php-mysql -y 

# exit 退出容器

# docker commit -m "Add LAMPenv" -a "CentOS_LAMP" e2d6c890682f 6.7lamp   提交更新后的副本

    -m message

    -a author

 

# docker images   可以看到已经生成了一个镜像

 

# docker run -i -t 6.7lamp/bin/bash      用刚才创建的镜像启动容器

 

另外,可以使用docker commit -m ‘my nignx‘ e2d6c890682fdemo/my_nginx:v1 这种创建带明显标志的镜像。

启动的话使用docker run -d -p 88:80 --name "ningx_1" demo/my_nginx:v1 即可。

 


方法2、dockerfile创建基于centos6.7nginx的容器

mkdir /opt/docker-file

cd /opt/docker-file

mkdir nginx && cd nginx

vi Dockerfile 内容如下:

# This is My First Dockerfile

# Verson 1.0

# Author: Lee

 

FROM centos:6.7

MAINTAINER Lee

ADD pcre-8.36.tar.gz/usr/local/src       <--- 1、需要事先把这个tar.gz包拷贝到当前目录下,即和Dockerfile在同一个目录下

ADD nginx-1.11.5.tar.gz/usr/local/src <---2、如果是个压缩包,拷到容器后会自动解压的,无需我们解压操作

 

RUN rm -fr /etc/yum.repos.d/*

RUN wget -O/etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-6.repo

RUN wget -O/etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-6.repo

RUN yum clean all

RUN yum install -y wget gcc gcc-c++ make openssl-devel

RUN useradd -s /sbin/nologin -Mwww

 

WORKDIR/usr/local/src/nginx-1.11.5

 

RUN ./configure--prefix=/usr/local/nginx --user=www --group=www --with-http_ssl_module --with-http_stub_status--with-pcre=/usr/local/src/pcre-8.36 && make && make install

RUN echo ‘daemon off;‘ >>/usr/local/nginx/conf/nginx.conf

RUN sed ‘s@#user  nobody;@user www;@g‘ nginx.conf

 

ENV PATH/usr/local/nginx/sbin:$PATH

EXPOSE 80

 

CMD ["nginx"]

 

docker build -t dockfile:v2 . 这样就可以创建镜像了

启动刚才创建的nginx docker容器的话,使用docker run -d -p 8888:80 dockfile:v2即可。


参数说明:

指令:

FROM <image>[:tag>]  或者FROM <image>@<digest>   # 必须是第一个非注释的行,用于指定所用到的基础镜像

MAINTAINER <author‘s detail>

 

COPY ["<src>", ..."<dest>"]       复制本地主机的目录到容器里的指定目录

    <src>是要复制的源文件或目录,支持通配符

    <dest>目标路径,正在创建的镜像文件的文件系统路径(建议使用绝对路径)

    说明:所有新复制生成的目录文件的UIDGID都是0

    例如: COPY /home/template/server.xml/etc/tomcat/server.xml

          COPY *.conf /etc/httpd/conf.d/

    注意:src 必须是build上下文的路径,即不能使用类似../../conf/*.conf,但是还是可以使用绝对路径例如/home/conf.d/*.conf src如果是目录的话,递归复制会自动进行;如果有多个src,包括在src上使用了通配符,此时dest必须是目录,而且必须得以/结尾。

       dest如果事先不存在,它会被自动创建,包括其父目录。

 

ADD     类似COPY指令,额外还支持复制tar格式的文件及URL路径。【ADDCOPY用得更常见些】

    例如:ADD haproxy.cfg /etc/haproxy/haproxy.cfg

     ADDlogstash_*.cnf /etc/logstash/

         ADD http://www.demo.com/download/nginx.conf/etc/nginx/ URL格式指定的源文件,下载完成后其目标文件权限为600

    如果src是一个宿主机上的tar文件,则它将被解压展开成要给目录(类似tar xf命令,如果通过URL下载的是个tar文件,则不会被自动展开)

 

ENV    定义环境变量,此些变量可以被当前dockerfile文件中的其它指令所调用,调用格式为$variable_name${variable_name}

    语法:

       ENV<key> <value>  一次定义一个变量

或者 ENV <key>=<value>...  一次可以定义多个变量,如果value中有空白字符,要是\进行转义

    如: ENV myName="Tom Lee" myDog=‘wang cai‘

    说明:ENV定义的环境变量在镜像运行的整个过程中一直存在,因此可以使用docker inspect查看,甚至可以用docker run --env=xxx 来修改其值

 

USER       指定运行容器时,或者运行RUN CMD ENTRYPOINT指令指定的程序时使用的用户名或者UID

    格式: USER <UID>|<Username>

 

WORKDIR    为后续的RUNCMDENTRYPOINTCOPYADD指令配置工作目录

    如:

    WORKDIR/a

    WORKDIRb

    WORKDIRc

    RUNpwd

    则最终路径为 /a/b/c

    另外,  WORKDIR还可以调用由ENV定义的环境变量的值,如: WORKDIR $STATEPATH

 

ENTRYPOINT

 

VOLUME     在目标镜像文件中创建一个挂载点,用来挂载主机上的卷或其他容器的卷。一般用来存放数据库和需要保持的数据等。

    VOLUME<mountpoint>

例如: VOLUME ["/data/mysql","/data/Images"]

注意:如果mountpoint路径下事先有文件存在,则在挂载完成后,会同时显示当前的文件和挂载前的文件(AUFS的叠加原理)。

 

RUN                          

    每个RUN都会另起一层,所以建议将多个命令放到一行,减少AUFS的层数。

    格式:

RUN <command>    # 会启动一个shell解释器

       RUN ["<executeable>","<param1>","<parma2>",...]       # 不会启动shell解释器

    例如:

       RUNyum install iproute nginx && yum clean all

RUN[‘/bin/bash‘,‘-c‘,‘yum‘,‘install‘,‘httpd‘]

 

CMD    设定docker run时默认执行的命令

    格式: CMD <command> CMD ["<executeable>","<param1>","<parma2>"]

CMD["<param1>","<param2>",...]  ENTRYPOINT指令指定的程序提供默认参数。

    如果dockerfile中存在多个CMD指令,则只有最后一个生效。

    例如:

       CMD["/usr/sbin/httpd","-c","/etc/httpd/conf/httpd.conf"]

 

ENTRYPOINT     类似CMD指令,但其不会被docker run的命令行参数指定的指令所覆盖。且这些命令行参数会被当中参数送给ENTRYPOINT指令指定的程序

    如果运行docker run时使用了--entrypoint选项,则此选项的参数可以覆盖掉dockerfile默认的entrypoint参数。

    格式:

       ENTRYPOUNT<command>

       ENTRYPOUNT["executeable","<param1>","<param2>",...] 

    例如:

    注意:

       如果CMDENTRYPOINT都存在的话,则CMD的指令会被附加到ENTRYPOINT后,变成ENTRYPOINT的参数。

 

EXPOSE     用于为容器指定要暴露的端口

    格式:EXPOSE<port>[/protocol>][<port>[/<protocol>]]...

    如:

       EXPOSE11211/tcp 11211/udp

 

ONBUILD    配置当所创建的镜像作为其它新创建镜像的基础镜像时,所执行的操作指令

    例如: ONBUILD ADD my.cnf /etc/mysql/my.cnf

    注意:ONBUILD不能自我嵌套,且不会触发。



 

导出镜像

# docker save -o/root/centos_lamp_v3.tar centos/lamp:v3

 

导入镜像

# docker load--input /root/centos_lamp_v3.tar

或者docker load </root/centos_lamp_v3.tar

# 这将导入镜像以及其相关的元数据信息(包括标签等)

 

移除镜像

# docker rmicentos/lamp:v3

注意:在删除镜像之前要先用dockerrm 删掉依赖于这个镜像的所有容器。

 

想要删除untagged images,也就是那些id<None>image的话可以用

# docker rmi$(docker images | grep "^<none>" | awk "{print $2}")

 

要删除全部image的话

# docker rmi$(docker images -q)

 

删除已停止的容器

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

 

移除容器

# docker rm5d6da6754d01

 

停止所有的container,这样才能够删除其中的images

# docker stop$(docker ps -a -q)

 

如果想要删除所有container的话再加一个指令:

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

 

从本地文件系统导入一个镜像

要从本地文件系统导入一个镜像,可以使用 openvz(容器虚拟化的先锋技术)的模板来创建: openvz

模板下载地址为 templates

比如,先下载了一个 ubuntu-14.04 的镜像,之后使用以下命令导入:

catubuntu-14.04-x86_64-minimal.tar.gz |docker import - ubuntu:14.04

 

上传镜像

docker pushouruser/sinatra

 

 

进入容器

在使用 -d 参数时,容器启动后会进入后台。某些时候需要进入容器进行操作,有很多种方法,包括使用docker attach 命令或 nsenter 工具等

# docker attach 容器NAME

或者docker exec-ti 容器ID /bin/bash


但是使用 attach 命令有时候并不方便。当多个窗口同时 attach 到同一个容器的时候,所有窗口都会同步显示。当某个窗口因命令阻塞时,其他窗口也无法执行操作了。使用attach进到容器后要退出的话,只能关闭xshell了,使用exit会导致整个容器的退出。

 

nsenter 这个进入容器的命令也很好用(如果没有的话需要安装util-linux-ng)。

方法:

dockerinspect  --format"{{.State.Pid}}" 容器NAME或者容器ID      # 结果会输出一个容器的pid

nsenter --target 容器的pid --mount --uts --ipc --net--pid

上面2条命令可以做成脚本,in.sh 内容如下:

#!/bin/bash

CNAME=$1

CPID=$(dockerinspect  --format"{{.State.Pid}}" $CNAME)

nsenter--target $CPID --mount --uts --ipc --net --pid

 

sh in.sh 容器的NAME或者ID号,即可进入容器。

 

 


导出容器快照到本地文件

# docker ps -a

# docker export 容器名称 > ubuntu.tar


导入容器快照为镜像

# cat ubuntu2.tar |docker import - test/ubuntu:v1

# docker images


自己基于centos构建nginx容器:

首先启动一个centos容器,然后在里面安装nginx(我这里是yum安装的nginx)。

修改nginx的配置文件,加上daemon off; 参数。

然后继续。下面有2种方法启动容器时候让它自动启动nginx

方法1

    dockercommit -m ‘nginx_v1‘ eb919426f773 6.7_nginx_v1

    dockerrun -d -p 888:88 --name ‘nginx_v1‘ 6.7_nginx_v1 /usr/sbin/nginx

    这样就可以了。

方法2

    修改容器的/etc/bashrc 加上/usr/sbin/nginx -c/etc/nginx/nginx.conf

    dockerrun -d -p 888:88 --name ‘nginx_v1‘ 6.7_nginx_v1 /bin/bash

 

docker私有仓库的搭建

【作为仓库的虚拟机IP:192.168.2.11】:

# 必须先启动docker registrycentos6上是这样的。在centos7上则变成了一个守护进程,需要用systemctl来启动】

# docker pullregistry

# docker run -d-p 5000:5000 -v /opt/data/registry:/tmp/registry registry

# docker ps   记下容器NAMEkickass_wright

# 默认情况下,仓库会被创建在容器的 /tmp/registry 下。可以通过 -v 参数来将镜像文件存放在本地的指定路径。

 

# docker images   列出当前的镜像

# docker tag88e44a5cbd17 192.168.2.11:5000/centos/lamp 

格式:dockertag [OPTIONS] IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]

# docker images


Docker1.3.X之后,与docker registry交互默认使用的是https,然而此处搭建的私有仓库只提供http服务,所以当与私有仓库交互时就会报上面的错误。为了解决这个问题需要在启动docker server时增加启动参数为默认使用http访问。

修改docker配置文件将代码加到/etc/sysconfig/dockerother_args="--insecure-registry192.168.2.11:5000"里面。

# docker stopkickass_wright       停掉registry容器

#/etc/init.d/docker restart    重启docker

# docker startkickass_wright      启动registry容器

# docker push192.168.2.11:5000/centos/lamp       将本地镜像推送到本机上的私有服务器上

这样本地镜像就是上次到私有docker 仓库了。

 

我们可以在其他节点测试能否下载这个镜像。如果没问题的话,就可以在本机上删除原有的docker镜像,如下:

# docker rmi 192.168.2.11:5000/centos/lamp

 

Node2节点(192.168.2.12)测试:

# yum installdocker-io -y

修改docker配置文件将代码加到/etc/sysconfig/dockerother_args="--insecure-registry192.168.2.11:5000"里面。

 

#/etc/init.d/docker restart    重启docker

 

# docker pull192.168.2.11:5000/centos/lamp          192.168.2.11的私有仓库下载镜像

# docker images      可以看到已经下载好了相关的镜像


docker的监控命令:

docker ps [-a]

docker images

docker stats Container_name # 实时查看某个容器的负载情况

docker top Container_name       # 实时查看某个容器的状态统计(类似top命令)

 dockerinspect   # 查看容器或镜像的底层信息

    例如:docker inspect -f‘{{.Config.Hostname}}‘ d413082da04e  类似ansible ansible -m setup的输出格式

 

此外,还有谷歌提供的CAdvisor web界面的监控工具;Scout工具,Data Dog工具,等。具体可参考: http://dockone.io/article/397

 


数据卷:

数据卷是一个可供一个或多个容器使用的特殊目录,它绕过 UFS,可以提供很多有用的特性:

  • 数据卷可以在容器之间共享和重用

  • 对数据卷的修改会立马生效

  • 对数据卷的更新,不会影响镜像

  • 卷会一直存在,直到没有容器使用

*数据卷的使用,类似于 Linux 下对目录或文件进行 mount

 

 

下面创建一个web 容器,并加载一个数据卷到容器的/webapp 目录:

# docker run -d-P --name web -v /webapp training/webapp python app.py  

# 这样只写名容器中的目录不写宿主机的目录的话,实际上是在宿主机的/var/lib/docker/volumes/xxxx/目录下的。不常用这种写法。

-v 标记来创建一个数据卷并挂载到容器里。在一次 run 中多次使用可以挂载多个数据卷

*注意:也可以在 Dockerfile 中使用 VOLUME 来添加一个或者多个新的卷到由该镜像创建的任意容器。

 

挂载一个主机目录src/webapp作为容器的数据卷:

# docker run -d-P --name web2 -v /src/webapp:/opt/webapp training/webapp python app.py

# 格式:-v 本地路径:容器路径

* 上面的命令加载主机的 /src/webapp 目录到容器的 /opt/webapp 目录。这个功能在进行测试的时候十分方便,比如用户可以放置一些程序到本地目录中,来查看容器是否正常工作。

* 本地目录的路径必须是绝对路径,如果目录不存在 Docker 会自动为你创建它

* 注意:Dockerfile 中不支持这种用法,这是因为 Dockerfile 是为了移植和分享用的。然而,不同操作系统的路径格式不一样,所以目前还不能支持。

 

Docker 挂载数据卷的默认权限是读写,用户也可以通过:ro 指定为只读

# sudo docker run-d -P --name web -v /src/webapp:/opt/webapp:ro training/webapppython app.py

 

-v 标记也可以从主机挂载单个文件到容器中

# docker run --rm-it -v ~/.bash_history:/.bash_history ubuntu /bin/bash   【不同shell版本有所不同】

*注意:如果直接挂载一个文件,很多文件编辑工具,包括 vi 或者 sed --in-place ,可能会造成文件inode 的改变,从 Docker 1.1 .0起,这会导致报错误信息。所以最简单的办法就直接挂载文件的父目录。

 

 

数据卷容器:

如果你有一些持续更新的数据需要在容器之间共享,最好创建数据卷容器。

数据卷容器,其实就是一个正常的容器,专门用来提供数据卷供其它容器挂载的。

 

首先,创建一个数据卷容器dbdata,并在其中创建一个数据卷挂载到/dbdata:

# docker run -i-t -v /dbdata --name dbdata ubuntu:12.04/bin/bash

                            技术分享

再启动2个容器测试

# docker run -i-t --volumes-from dbdata --name db1 ubuntu:12.04/bin/bash

# docker run -i-t --volumes-from dbdata --name db2 ubuntu:12.04/bin/bash

# 注意:--volumes-from后面跟的是具备容器卷的那个容器名

此时容器db1db2都挂载同一个数据卷到相同的/dbdata目录。三个容器任何一方在该目录下的写入,其他容器都可以看到。[即便原来的那个数据卷容器已经停止了]

 

查看数据卷实际的存放路径:

docker inspect -f{{.Volumes}} 数据卷容器的NAMEID

map[/dbdata:/var/lib/docker/volumes/7c12ca73fe29f884ea5bee12c54da521c7450705264f76fe8629877302cd48aa/_data]

可以看到这个容器卷是把文件写入到/var/lib/docker/volumes下面的某个很长的字符串的目录下的_data/里面

 

容器和宿主机间文件拷贝的解决方法:

docker ps 获取目标容器的ID或者容器的名称    # 我这里的是容器ID52261df2fab6

docker inspect-f‘{{.Id}}‘ 容器的ID      # 获取容器的ID全名称

得到一串类似52261df2fab612b24b3502c4ad98c22aff70ce9fa641c5c9f735ac2415e92da3

cp /root/test.log/var/lib/docker/devicemapper/mnt/52261d...xxx/rootfs/root/   # 这样就把宿主机的test.log拷贝到容器的/root/目录下了。

 

# 说明:上面的这个方法在CentOS6.7通过yum安装的docker-io测试通过。我另一台测试机安装的是docker-engine,则根本没有/rootfs/这个目录。

 

 

还可以使用多个--volumes-from 参数来从多个容器挂载多个数据卷。

# docker run -i-t -v /dbdata --name dbdata ubuntu:12.04/bin/bash

# docker run -i-t -v /webdata --name webdata ubuntu:12.04/bin/bash

# docker run -i-t --volumes-from dbdata --name db1 --volumes-fromwebdata --name web1 ubuntu:12.04 /bin/bash

此外,也可以从其他已经挂载了数据卷的容器来挂载数据卷。

 

*注意:

使用 --volumes-from 参数所挂载数据卷的容器自己并不需要保持在运行状态。

如果删除了挂载的容器(包括 dbdatadb1 db2),数据卷并不会被自动删除。

如果要删除一个数据卷,必须在删除最后一个还挂载着它的容器时使用 "docker rm -v 容器名" 命令来指定同时删除关联的容器。这可以让用户在容器之间升级和移动数据卷。另外,如果启动时候加了--rm参数,则容器关闭时自动删除容器并删除卷。

 

 

利用数据卷容器来备份数据

# docker run -i-t -v /dbdata --name dbdata ubuntu:12.04 /bin/bash

# cp /etc/issue/etc/group /dbdata

另外启动一个容器,对刚才的容器数据进行备份操作

# docker run --volumes-fromdbdata -v $(pwd):/backup --name bk1 ubuntu:12.04 tar czf/backup/backup.tar.gz /dbdata

# 格式:dockerrun --volumes-from要备份的容器名-v 宿主机目录:/backup ubuntu:12.04 tar czf /backup/xx.tar.gz 需要备份的容器的卷名称

*容器启动后,使用了 tar 命令来将 dbdata 卷备份为容器下的/backup/backup.tar.gz,这个容器执行完就自动退出了(因为没有-ti -d参数),

*同时在宿主机下当前目录下生成backup.tar.gz压缩文件(参数-v $(pwd):/backup就是这个作用).

 

利用数据卷容器来恢复数据

如果要恢复数据到一个容器,首先创建一个带有数据卷的容器 dbdata2

# docker run -it-v /dbdata --name dbdata2 ubuntu:12.04 /bin/bash

随便在/dbdata里面复制些文件,以便后面恢复数据时用于识别。

然后创建另一个容器,挂载 dbdata2 的容器,并使用tar解压备份文件到挂载的容器卷中。

#docker run --volumes-from dbdata2 -v $(pwd):/backup ubuntu:12.04 tar xf/backup/backup.tar.gz

 

 




docker入门篇