Dockerfile

小例子: 

在linux系统中使用 get clone https://git.oschina.net/wq3435/docker-training.git 进行克隆

进入 centos7中 

从centos7中得到这样一个Dockerfile,安装了一些基础工具和软件

1. Dockerfile 指令详解:

#
# MAINTAINER        Carson,C.J.Zeong <zcy@nicescale.com>
# DOCKER-VERSION    1.6.2
#
# Dockerizing CentOS7: Dockerfile for building CentOS images
#
FROM       centos:centos7.1.1503  #FROM指令 想要构建一个Docker镜像,必须先有一个基础镜像(父镜像),这个镜像可以直接从Docker Hub上 pull回来,也可以自己制作一个镜像
MAINTAINER Carson,C.J.Zeong <zcy@nicescale.com>  #MAINTAINER 表明这个DockerFile由谁来维护  名字 邮箱

ENV TZ "Asia/Shanghai" #ENV (Environment)环境 指定了一个时区 环境变量可以写多个
ENV TERM xterm

#在 Dockerfile 中有两条指令可以 copy文件 一个是ADD 一个是COPY ,这两个都是复制文件到 Container里边,有什么不同呢?
# ADD 命令要比 COPY命令多两个动能 :1.可以拷贝一个WebServer上的一个文件(可以以一个链接的形式) 到 Container中
# 2.拷贝一个压缩包到Container中可以自动进行解压,不需要手动进行 tar命令解压
# copy 只支持把本地文件拷贝到Container里面
ADD aliyun
-mirror.repo /etc/yum.repos.d/CentOS-Base.repo ADD aliyun-epel.repo /etc/yum.repos.d/epel.repo
# RUN 命令后边可以直接执行 Linux Shell命令 每执行一次命令都会有一个新的层产生 RUN
yum install -y curl wget tar bzip2 unzip vim-enhanced passwd sudo yum-utils hostname net-tools rsync man && \ yum install -y gcc gcc-c++ git make automake cmake patch logrotate python-devel libpng-devel libjpeg-devel && \ yum install -y --enablerepo=epel pwgen python-pip && \ yum clean all RUN pip install supervisor #使用 supervisor(进程管理工具) 可以管理进程,如果是单个进程 supervisor 可以直接不写 ADD supervisord.conf /etc/supervisord.conf # 添加 supervisor 的主配置文件到 /etc下 RUN mkdir -p /etc/supervisor.conf.d && \ #创建/etc/supervisor.conf.d 目录,这个目录下会存放其他服务的配置文件
mkdir -p /var/log/supervisor # 存放 supervisor的日志目录

EXPOSE
22 #给宿主机暴露一个端口,进行端口映射后可以使用端口号连接到这个Container容器中

ENTRYPOINT [
"/usr/bin/supervisord", "-n", "-c", "/etc/supervisord.conf"] # 只有最后一条 ENTRYPOINT会生效,Container每次启动时会执行 ENTRYPOINT
#这里的主要作用是开启supervisor 的服务,并加载配置文件

 

2. 执行命令:

docker build -t csphere/centos:7.1 .

 

docker build 使用一个 Dockerfile 生成一个 Docker镜像

-t 给我要生成的Docker镜像起一个名字 一个docker镜像最完整的的命名: registry_url/namespace/csphere/centos:7.1  其中7.1代表要创建的镜像版本,如果没有写默认会加上一个tag,即registry_url/namespace/csphere/centos:latest

. 指定Dockerfile的位置,如果Dockerfile这个文件在此目录下,直接使用 . 表示,如果不在当前目录下需要写一个相对路径: ./path...

运行命令后可以使用 docker images 查看本地有哪些镜像

 

3. 有了镜像之后,可以使用 docker run 将镜像变成容器:

docker run [-it|-d] -p 2222:22 --name base csphere/centos:7.1

-it 采用交互的方式

-d 把Container在后台启动以后,Container会返回一个ContainerID

-P 22 设置这个参数后 表明容器暴露的端口为22 宿主机会随机的找一个没有被使用的 端口号和 22 这个端口进行映射(假如随机2222:22) 即可以在外部直接使用 2222 端口直接访问容器,在宿主机重启后又会找一个随机未被使用的端口号进行映射

-p 2222:22 不管是宿主机重启还是Container重启,这个2222一直会给22端口映射,除非这个Container删掉以后会把这个2222给其他的Container

--name 通过docker镜像生成docker 容器,给docker容器起一个名字以方便以后去查找

使用 csphere/centos:7.1 来创建叫做base的docker容器

 

4. 创建了容器想看容器的状态,容器的相关信息

docker ps 查看Running状态的Container

docker ps -a 查看所有状态的Container

 

5. 基础镜像 -> 中间件镜像 -> 应用镜像

  5.1 安装中间件镜像:

    进入 php-fpm

  查看php-fpm/Dockerfile

  

#
# MAINTAINER        Carson,C.J.Zeong <zcy@nicescale.com>
# DOCKER-VERSION    1.6.2
#
# Dockerizing php-fpm: Dockerfile for building php-fpm images
#
FROM       csphere/centos:7.1  #选择csphere/centos7.1 作为基础镜像
MAINTAINER Carson,C.J.Zeong <zcy@nicescale.com>

# Set environment variable
ENV    APP_DIR /app

# 主要安装的软件 nginx php-mysql php-fpm 以及其他一些php拓展包 RUN
yum -y swap -- remove fakesystemd -- install systemd systemd-libs && \ yum -y install nginx php-cli php-mysql php-pear php-ldap php-mbstring php-soap php-dom php-gd php-xmlrpc php-fpm php-mcrypt && \ yum clean all ADD nginx_nginx.conf /etc/nginx/nginx.conf ADD nginx_default.conf /etc/nginx/conf.d/default.conf ADD php_www.conf /etc/php-fpm.d/www.conf RUN sed -i 's/;cgi.fix_pathinfo=1/cgi.fix_pathinfo=0/' /etc/php.ini RUN mkdir -p /app && echo "<?php phpinfo(); ?>" > ${APP_DIR}/info.php EXPOSE 80 443 ADD supervisor_nginx.conf /etc/supervisor.conf.d/nginx.conf ADD supervisor_php-fpm.conf /etc/supervisor.conf.d/php-fpm.conf ONBUILD ADD . /app # ONBUILD 在当前镜像不生效,在下一个以当前镜像为基础镜像的的镜像重生效 ONBUILD RUN chown -R nginx:nginx /app

 

 

进入到Container内部:

docker exec -it website /bin/bash

 

 不推荐使用 attach ,使用attach 在退出Container时 Container会挂掉

因为使用的时Centos作为基础镜像,所以进入Container后就有了Centos的所有功能

进入容器后可以使用 supervisorctl查看所有已启动的服务

可以使用exit 退出容器

 

VOLUME ["/var/lib/mysql"] 把Container中的目录映射到宿主机的目录,作用是在删除Container时,可以将数据保留下来

 

 

测试:

1. 写一个Dockerfile  基于Centos 环境安装配置 jdk,tomcat,maven环境

可以采用 wget在线下载的方式,也可以采用先将需要安装的包下载好然后,然后使用ADD 的方式进行复制和解压操作

先进行 Dockerfile 文件的编辑

vim Dockerfile

FROM centos

#MAINTAINER Wq ""

#安装wget工具
RUN yum -y install wget

#设置工作目录
#WORKDIR /home

#安装jdk
RUN mkdir /var/tmp/jdk
#RUN wget --no-check-certificate --no-cookies --header "Cookie: oraclelicense=accept-securebackup-cookie"  -P /var/tmp/jdk http://download.oracle.com/otn-pub/java/jdk/8u111-b14/jdk-8u111-linux-x64.tar.gz
#RUN tar xzf /var/tmp/jdk/jdk-8u111-linux-x64.tar.gz -C /var/tmp/jdk
#RUN rm -rf /var/tmp/jdk/jdk-8u111-linux-x64.tar.gz
#使用本地已经下载好的tar包
ADD ./jdk-8u111-linux-x64.tar.gz /var/tmp/jdk

#安装tomcat
RUN mkdir /var/tmp/tomcat
#RUN wget -P /var/tmp/tomcat http://mirrors.hust.edu.cn/apache/tomcat/tomcat-8/v8.5.8/bin/apache-tomcat-8.5.8.tar.gz
#RUN tar xzf /var/tmp/tomcat/apache-tomcat-8.5.8.tar.gz -C /var/tmp/tomcat
#RUN rm -rf /var/tmp/tomcat/apache-tomcat-8.5.8.tar.gz
ADD ./apache-tomcat-8.5.11.tar.gz /var/tmp/tomcat

#安装maven
RUN mkdir /var/tmp/maven
#RUN wget -P /var/tmp/maven  http://apache.fayea.com/maven/maven-3/3.3.9/binaries/apache-maven-3.3.9-bin.tar.gz
#RUN tar xzf /var/tmp/maven/apache-maven-3.3.9-bin.tar.gz -C /var/tmp/maven
#RUN rm -rf /var/tmp/maven/apache-maven-3.3.9-bin.tar.gz
ADD ./apache-maven-3.3.9-bin.tar.gz /var/tmp/maven

#设置环境变量
ENV JAVA_HOME /var/tmp/jdk/jdk1.8.0_111
ENV CATALINA_HOME /var/tmp/tomcat/apache-tomcat-8.5.11
ENV M2_HOME /var/tmp/maven/apache-maven-3.3.9
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/bin:$M2_HOME/bin
ENV CLASSPATH .:$JAVA_HOME/lib:$JAVA_HOME/jre/lib\

#打包项目并拷贝到tomcat webapps目录
#RUN mkdir /var/tmp/webapp
#ADD ./ /var/tmp/webapp
#RUN cd /var/tmp/webapp && mvn package && cp /var/tmp/webapp/target/CIJD.war /var/tmp/tomcat/apache-tomcat-8.5.8/webapps

#开启内部服务端口
EXPOSE 8080

#启动tomcat服务器
CMD ["./var/tmp/tomcat/apache-tomcat-8.5.11/bin/catalina.sh","run"] 

 

2.这里编辑好的Dockerfile与需要安装的包在同一个目录,在Dockerfile中使用相对路径,当然也可以不放在同一个目录下

[hadoop@hadoop dockerJavaTomcat]$ ls
apache-maven-3.3.9-bin.tar.gz  apache-tomcat-8.5.11.tar.gz  Dockerfile  jdk-8u111-linux-x64.tar.gz

3. 使用 sudo docker build -t  自定义镜像名称 .  命令使用Dockerfile生成 镜像,注意末尾的 .  代表当前目录

[hadoop@hadoop dockerJavaTomcat]$ sudo docker build -t test/centos .
Sending build context to Docker daemon 199.2 MB
Step 1/14 : FROM centos
 ---> 67591570dd29
Step 2/14 : RUN yum -y install wget
 ---> Running in 68c6aee19401
Loaded plugins: fastestmirror, ovl
Determining fastest mirrors
 * base: mirrors.yun-idc.com
 * extras: mirrors.btte.net
 * updates: mirrors.btte.net
Resolving Dependencies
--> Running transaction check
---> Package wget.x86_64 0:1.14-13.el7 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

================================================================================
 Package         Arch              Version                Repository       Size
================================================================================
Installing:
 wget            x86_64            1.14-13.el7            base            546 k

Transaction Summary
================================================================================
Install  1 Package

Total download size: 546 k
Installed size: 2.0 M
Downloading packages:
warning: /var/cache/yum/x86_64/7/base/packages/wget-1.14-13.el7.x86_64.rpm: Header V3 RSA/SHA256 Signature, key ID f4a80eb5: NOKEY
Public key for wget-1.14-13.el7.x86_64.rpm is not installed
Retrieving key from file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
Importing GPG key 0xF4A80EB5:
 Userid     : "CentOS-7 Key (CentOS 7 Official Signing Key) <security@centos.org>"
 Fingerprint: 6341 ab27 53d7 8a78 a7c2 7bb1 24c6 a8a7 f4a8 0eb5
 Package    : centos-release-7-3.1611.el7.centos.x86_64 (@CentOS)
 From       : /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
  Installing : wget-1.14-13.el7.x86_64                                      1/1 
install-info: No such file or directory for /usr/share/info/wget.info.gz
  Verifying  : wget-1.14-13.el7.x86_64                                      1/1 

Installed:
  wget.x86_64 0:1.14-13.el7                                                     

Complete!
 ---> 55186d4b374b
Removing intermediate container 68c6aee19401
Step 3/14 : RUN mkdir /var/tmp/jdk
 ---> Running in 9520a429f48b
 ---> cd34a70476a9
Removing intermediate container 9520a429f48b
Step 4/14 : ADD ./jdk-8u111-linux-x64.tar.gz /var/tmp/jdk
 ---> eda2e5beeb96
Removing intermediate container 136b3399cbb0
Step 5/14 : RUN mkdir /var/tmp/tomcat
 ---> Running in a7993e699bc2
 ---> 7f4f232d403d
Removing intermediate container a7993e699bc2
Step 6/14 : ADD ./apache-tomcat-8.5.11.tar.gz /var/tmp/tomcat
 ---> e062597baa3f
Removing intermediate container 504ad9134e9f
Step 7/14 : RUN mkdir /var/tmp/maven
 ---> Running in eb4f0a6c1b53
 ---> 71c23553ad63
Removing intermediate container eb4f0a6c1b53
Step 8/14 : ADD ./apache-maven-3.3.9-bin.tar.gz /var/tmp/maven
 ---> 4cd9fc650579
Removing intermediate container a704eb8d05ad
Step 9/14 : ENV JAVA_HOME /var/tmp/jdk/jdk1.8.0_111
 ---> Running in 6350e074c53a
 ---> f3ed5cf892dd
Removing intermediate container 6350e074c53a
Step 10/14 : ENV CATALINA_HOME /var/tmp/tomcat/apache-tomcat-8.5.11
 ---> Running in 4f1882af894d
 ---> ac468a76d496
Removing intermediate container 4f1882af894d
Step 11/14 : ENV M2_HOME /var/tmp/maven/apache-maven-3.3.9
 ---> Running in 3a4d04147215
 ---> 960c9cae9608
Removing intermediate container 3a4d04147215
Step 12/14 : ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/bin:$M2_HOME/bin
 ---> Running in c41f424f228f
 ---> 3bbc4fd29d09
Removing intermediate container c41f424f228f
Step 13/14 : ENV CLASSPATH .:$JAVA_HOME/lib:$JAVA_HOME/jre/libEXPOSE 8080
 ---> Running in 0bf7d5d982ca
 ---> 2c198b2fa6c2
Removing intermediate container 0bf7d5d982ca
Step 14/14 : CMD ./var/tmp/tomcat/apache-tomcat-8.5.11/bin/catalina.sh run
 ---> Running in fd2c012070da
 ---> 0235ea6a1dc1
Removing intermediate container fd2c012070da
Successfully built 0235ea6a1dc1

最后的 Successfully built 0235ea6a1dc1 代表成功,这里step为步骤,每一步都会产生一个layer

产看已经image已经生成

[hadoop@hadoop dockerJavaTomcat]$ sudo docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
test/centos         latest              0235ea6a1dc1        14 minutes ago      655 MB
<none>              <none>              f07e6d9bd519        About an hour ago   192 MB
ubuntu              latest              0ef2e08ed3fa        37 hours ago        130 MB
ubuntu              14.04               7c09e61e9035        37 hours ago        188 MB
docker-whale        latest              17104b3a899f        2 days ago          256 MB
hello-world         latest              48b5124b2768        6 weeks ago         1.84 kB
centos              latest              67591570dd29        2 months ago        192 MB
docker/whalesay     latest              6b362a9f73eb        21 months ago       247 MB
[hadoop@hadoop dockerJavaTomcat]$ 

4. 将 镜像 装载为容器

[hadoop@hadoop dockerJavaTomcat]$ sudo docker run -it -p 8090:8080 --name testContainer test/centos
Using CATALINA_BASE:   /var/tmp/tomcat/apache-tomcat-8.5.11
Using CATALINA_HOME:   /var/tmp/tomcat/apache-tomcat-8.5.11
Using CATALINA_TMPDIR: /var/tmp/tomcat/apache-tomcat-8.5.11/temp
Using JRE_HOME:        /var/tmp/jdk/jdk1.8.0_111
Using CLASSPATH:       /var/tmp/tomcat/apache-tomcat-8.5.11/bin/bootstrap.jar:/var/tmp/tomcat/apache-tomcat-8.5.11/bin/tomcat-juli.jar
01-Mar-2017 09:11:38.888 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version:        Apache Tomcat/8.5.11
01-Mar-2017 09:11:38.892 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server built:          Jan 10 2017 21:02:52 UTC
01-Mar-2017 09:11:38.892 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server number:         8.5.11.0
01-Mar-2017 09:11:38.893 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Name:               Linux
01-Mar-2017 09:11:38.893 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Version:            3.10.0-514.el7.x86_64
01-Mar-2017 09:11:38.893 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Architecture:          amd64
01-Mar-2017 09:11:38.894 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Java Home:             /var/tmp/jdk/jdk1.8.0_111/jre
01-Mar-2017 09:11:38.894 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Version:           1.8.0_111-b14
01-Mar-2017 09:11:38.894 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Vendor:            Oracle Corporation
01-Mar-2017 09:11:38.895 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_BASE:         /var/tmp/tomcat/apache-tomcat-8.5.11
01-Mar-2017 09:11:38.895 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_HOME:         /var/tmp/tomcat/apache-tomcat-8.5.11
01-Mar-2017 09:11:38.896 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.config.file=/var/tmp/tomcat/apache-tomcat-8.5.11/conf/logging.properties
01-Mar-2017 09:11:38.896 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
01-Mar-2017 09:11:38.896 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djdk.tls.ephemeralDHKeySize=2048
01-Mar-2017 09:11:38.897 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.protocol.handler.pkgs=org.apache.catalina.webresources
01-Mar-2017 09:11:38.897 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.base=/var/tmp/tomcat/apache-tomcat-8.5.11
01-Mar-2017 09:11:38.897 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.home=/var/tmp/tomcat/apache-tomcat-8.5.11
01-Mar-2017 09:11:38.897 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.io.tmpdir=/var/tmp/tomcat/apache-tomcat-8.5.11/temp
01-Mar-2017 09:11:38.898 INFO [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: /usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib
01-Mar-2017 09:11:39.104 INFO [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["http-nio-8080"]
01-Mar-2017 09:11:39.133 INFO [main] org.apache.tomcat.util.net.NioSelectorPool.getSharedSelector Using a shared selector for servlet write/read
01-Mar-2017 09:11:39.146 INFO [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["ajp-nio-8009"]
01-Mar-2017 09:11:39.151 INFO [main] org.apache.tomcat.util.net.NioSelectorPool.getSharedSelector Using a shared selector for servlet write/read
01-Mar-2017 09:11:39.152 INFO [main] org.apache.catalina.startup.Catalina.load Initialization processed in 829 ms
01-Mar-2017 09:11:39.197 INFO [main] org.apache.catalina.core.StandardService.startInternal Starting service Catalina
01-Mar-2017 09:11:39.198 INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet Engine: Apache Tomcat/8.5.11
01-Mar-2017 09:11:39.227 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory /var/tmp/tomcat/apache-tomcat-8.5.11/webapps/ROOT
01-Mar-2017 09:11:50.390 INFO [localhost-startStop-1] org.apache.catalina.util.SessionIdGeneratorBase.createSecureRandom Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [10,748] milliseconds.
01-Mar-2017 09:11:50.442 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory /var/tmp/tomcat/apache-tomcat-8.5.11/webapps/ROOT has finished in 11,216 ms
01-Mar-2017 09:11:50.443 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory /var/tmp/tomcat/apache-tomcat-8.5.11/webapps/docs
01-Mar-2017 09:11:50.494 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory /var/tmp/tomcat/apache-tomcat-8.5.11/webapps/docs has finished in 51 ms
01-Mar-2017 09:11:50.495 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory /var/tmp/tomcat/apache-tomcat-8.5.11/webapps/examples
01-Mar-2017 09:11:50.983 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory /var/tmp/tomcat/apache-tomcat-8.5.11/webapps/examples has finished in 488 ms
01-Mar-2017 09:11:50.984 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory /var/tmp/tomcat/apache-tomcat-8.5.11/webapps/host-manager
01-Mar-2017 09:11:51.020 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory /var/tmp/tomcat/apache-tomcat-8.5.11/webapps/host-manager has finished in 36 ms
01-Mar-2017 09:11:51.021 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory /var/tmp/tomcat/apache-tomcat-8.5.11/webapps/manager
01-Mar-2017 09:11:51.057 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory /var/tmp/tomcat/apache-tomcat-8.5.11/webapps/manager has finished in 36 ms
01-Mar-2017 09:11:51.066 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler [http-nio-8080]
01-Mar-2017 09:11:51.076 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler [ajp-nio-8009]
01-Mar-2017 09:11:51.080 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 11927 ms

[hadoop@hadoop dockerJavaTomcat]$ 
 sudo docker run -it -p 8090:8080 --name testContainer test/centos

-it 采用交互的方式

-d 把Container在后台启动以后,Container会返回一个ContainerID

-P 22 设置这个参数后 表明容器暴露的端口为22 宿主机会随机的找一个没有被使用的 端口号和 22 这个端口进行映射(假如随机2222:22) 即可以在外部直接使用 2222 端口直接访问容器,在宿主机重启后又会找一个随机未被使用的端口号进行映射

-p 2222:22 不管是宿主机重启还是Container重启,这个2222一直会给22端口映射,除非这个Container删掉以后会把这个2222给其他的Container

--name 通过docker镜像生成docker 容器,给docker容器起一个名字以方便以后去查找

使用 tset/centos 来创建叫做base的docker容器

由于采用了 -it 交互的方式运行,会直接进入容器内部,显示的是tomcat的启动

可以使用 Ctrl+P + Ctrl+Q 的方式 退出容器返回到宿主机中,此时容器依旧在后台运行

5.通过宿主机器的ip:映射端口 访问容器tomcat服务器

测试成功:

 

指令详解:

来自:http://www.cnblogs.com/51kata/p/5262301.html

CMD:

我们知道,通过docker run 创建并启动一个容器时,命令的最后可以指定容器启动后在容器内立即要执行的指令,如:

docker run -i -t ubunu /bin/bash   //表示容器启动时立即在容器内打开一个shell终端

docker run ubuntu /bin/ps    //表示容器启动后立即运行 /bin/ps命令,显示容器的当前进程。

除了这种方式外,我们可以在dockerfile文件中通过CMD指令指定容器启动时要执行的命令。如:

复制代码
#test
FROM ubuntu
MAINTAINER xxx
RUN echo hello1 > test1.txt
RUN echo hello2 > /test2.txt
EXPOSE 80
EXPOSE 81
CMD ["/bin/bash"]
复制代码

上面dockerfile文件中最后一行CMD指令的参数是指定容器启动时要执行的命令,这里是bin/bash命令。

1、用docker run命令创建并启动容器(myimage  是用前面dockerfile创建的镜像的名称):

docker run -i -t myimage  

上面命令是创建并启动容器,打开一个交互式shell。 而以前的写法是

docker run -i -t myimage  /bin/bash

这样就省去了在docker run中写命令了。

 

2、即使dockerfile中有CMD指令,我们仍然可以在docker run命令中带上容器启动时执行的命令,这会覆盖dockerfile中的CMD指令指定的命令。如:

docker run -i -t myimage /bin/ps

上面命令,因为/bin/ps覆盖了CMD指令,启动容器时会打印容器内的当前进程,但容器会立即停止,因为/bin/bash被覆盖了,无法打开交互式shell界面。

 

3、需要注意的是,dockerfile中可以有多条cmd命令,但只是最后一条有效。

 

4、CMD命令的参数格式,一般写成 字符串数组的方式,如上面的例子。如:

CMD  ["echo","hello world"]

虽然也可写成CMD echo hello word 方式,但这样docker会在指定的命令前加  /bin/sh -c 执行,有时有可能会出问题。 所以推荐采用数据结构的方式来存放命令。

ENTRYPOINT:

本文介绍Dockerfile的 ENTRYPOINT指令的含义。

先回顾下CMD指令的含义,CMD指令可以指定容器启动时要执行的命令,但它可以被docker run命令的参数覆盖掉。

ENTRYPOINT 指令和CMD类似,它也可用户指定容器启动时要执行的命令,但如果dockerfile中也有CMD指令,CMD中的参数会被附加到ENTRYPOINT 指令的后面。 如果这时docker run命令带了参数,这个参数会覆盖掉CMD指令的参数,并也会附加到ENTRYPOINT 指令的后面。

这样当容器启动后,会执行ENTRYPOINT 指令的参数部分。

可以看出,相对来说ENTRYPOINT指令优先级更高。

我们来看个例子,下面是Dockerfile的内容

复制代码
#test
FROM ubuntu
MAINTAINER hello
RUN echo hello1 > test1.txt
RUN echo hello2 > /test2.txt
EXPOSE 80
ENTRYPOINT ["echo"]
CMD ["defaultvalue"]
复制代码

假设通过该Dockerfile构建的镜像名为 myimage。

 

1、当运行 docker run myimage  输出的内容是 defaultvalue,可以看出CMD指令的参数得确是被添加到ENTRYPOINT指令的后面,然后被执行。


2、当运行docker run myimage hello world  输出的内容是 hello world ,可以看出docker run命令的参数得确是被添加到ENTRYPOINT指令的后面,然后被执行,这时CMD指令被覆盖了。

 

3、另外我们可以在docker run命令中通过 --entrypoint 覆盖dockerfile文件中的ENTRYPOINT设置,如:

docker run --entrypoint="echo" myimage good  结果输出good

 注意,不管是哪种方式,创建容器后,通过 dokcer ps查看容器信息时,COMMOND列会显示最终生效的启动命令。

WORKDIR:

Dockerfile中的WORKDIR指令用于指定容器的一个目录, 容器启动时执行的命令会在该目录下执行。

相当于设置容器的工作目录了。我们来看一个dockerfile文件

复制代码
#test
FROM ubuntu
MAINTAINER hello
RUN mkdir /mydir
RUN echo hello world > /mydir/test.txt
WORKDIR /mydir
CMD ["more" ,"test.txt"]
复制代码

假设根据该dockerfile构建的镜像名为 myimage

1、运行 docker run myimage  输出 hello world

2、运行 docker run myimage more test.txt  和上面输出一致

可以看出,more的参数是 test.txt,但没有指定路径,却能成功,说明当前路径就是上面WORKDIR指令设置的。

如果我们在上面的dockerfile中把WORKDIR指令去掉,创建的容器运行会报文件不存在错误。

 

3、可以在 docker run命令中用 -w参数覆盖掉WORKDIR指令的设置,如:

执行 docker run -w / myimage

上面的-w参数将容器的工作目录设置成了根目录,而根目录下没有test.txt文件。

所以结果显示:test.txt: No such file or directory

ENV:

ENV指令用来在镜像构建过程中设置环境变量。我们来看一个Dockerfile的例子:

复制代码
#test
FROM ubuntu
MAINTAINER hello
ENV MYDIR /mydir
RUN mkdir $MYDIR
RUN echo hello world > $MYDIR/test.txt
复制代码

假设用上面的dockerfile构建了一个叫myimage的镜像。
运行  docker run -i -t myimage /bin/bash

我们发现新建的容器中有了 /mydir目录,并有了/mydir/test.txt文件,文件内容为 hello world

1、通过ENV定义的环境变量,可以被后面的所有指令中使用,如上面的例子

2、但是不能被CMD指令使用,也不能被docker run 的命令参数引用。这个需要注意

3、通过ENV定义的环境变量,会永久的保存到该镜像创建的任何容器中。这样除了不能在上面说的启动命令中使用外,可以在后续容器的操作中使用。

4、可以在docker run 命令中通过 -e标记来传递环境变量,这样容器运行时就可以使用该变量。如:

docker run -i -t -e "TEST=hello" ubuntu /bin/bash

USER:

USER指令用于指定容器执行程序的用户身份,默认是 root用户。

在docker run 中可以通过 -u 选项来覆盖USER指令的设置。

举例:docker run -i -t -u mysql newmysqldb /bin/bash

显示的shell提示符是:

mysql@57cd57edba38:/$

注意:docker容器中的root用户密码是随机分配的。

ADD & COPY:

ADD指令的功能是将主机构建环境(上下文)目录中的文件和目录、以及一个URL标记的文件 拷贝到镜像中。

其格式是: ADD  源路径  目标路径

如:

复制代码
#test
FROM ubuntu
MAINTAINER hello
ADD test1.txt test1.txt
ADD test1.txt test1.txt.bak
ADD test1.txt /mydir/
ADD data1  data1
ADD data2  data2
ADD zip.tar /myzip
复制代码

有如下注意事项:

1、如果源路径是个文件,且目标路径是以 / 结尾, 则docker会把目标路径当作一个目录,会把源文件拷贝到该目录下。

如果目标路径不存在,则会自动创建目标路径。

2、如果源路径是个文件,且目标路径是不是以 / 结尾,则docker会把目标路径当作一个文件。

如果目标路径不存在,会以目标路径为名创建一个文件,内容同源文件;

如果目标文件是个存在的文件,会用源文件覆盖它,当然只是内容覆盖,文件名还是目标文件名。

如果目标文件实际是个存在的目录,则会源文件拷贝到该目录下。 注意,这种情况下,最好显示的以 / 结尾,以避免混淆。

3、如果源路径是个目录,且目标路径不存在,则docker会自动以目标路径创建一个目录,把源路径目录下的文件拷贝进来。

如果目标路径是个已经存在的目录,则docker会把源路径目录下的文件拷贝到该目录下。

4、如果源文件是个归档文件(压缩文件),则docker会自动帮解压。

COPY:

COPY指令和ADD指令功能和使用方式类似。只是COPY指令不会做自动解压工作。

 

ONBUILD:

ONBUILD指令可以为镜像添加触发器。其参数是任意一个Dockerfile 指令。

当我们在一个Dockerfile文件中加上ONBUILD指令,该指令对利用该Dockerfile构建镜像(比如为A镜像)不会产生实质性影响。

但是当我们编写一个新的Dockerfile文件来基于A镜像构建一个镜像(比如为B镜像)时,这时构造A镜像的Dockerfile文件中的ONBUILD指令就生效了,在构建B镜像的过程中,首先会执行ONBUILD指令指定的指令,然后才会执行其它指令。

需要注意的是,如果是再利用B镜像构造新的镜像时,那个ONBUILD指令就无效了,也就是说只能再构建子镜像中执行,对孙子镜像构建无效。其实想想是合理的,因为在构建子镜像中已经执行了,如果孙子镜像构建还要执行,相当于重复执行,这就有问题了。

利用ONBUILD指令,实际上就是相当于创建一个模板镜像,后续可以根据该模板镜像创建特定的子镜像,需要在子镜像构建过程中执行的一些通用操作 就可以在模板镜像对应的dockerfile文件中用ONBUILD指令指定。 从而减少dockerfile文件的重复内容编写。

 

我们来看一个简单例子。

1、先编写一个Dockerfile文件,内容如下:

#test
FROM ubuntu
MAINTAINER hello
ONBUILD RUN mkdir mydir

利用上面的dockerfile文件构建镜像: docker build -t imagea .
利用imagea镜像创建容器: docker run --name test1 -it imagea /bin/bash

我们发现test1容器的根目录下并没有mydir目录。说明ONBUILD指令指定的指令并不会在自己的构建中执行。

2、再编写一个新的Dockerfile文件,内容 如下

#test
FROM imagea
MAINTAINER hello1

注意,该构建准备使用的基础镜像是上面构造出的镜像imagea
利用上面的dockerfile文件构建镜像: docker build -t imageb .
利用imagea镜像创建容器: docker run --name test2 -it imageb /bin/bash

我们发现test2容器的根目录下有mydir目录,说明触发器执行了。 这个其实从构建imageb的输出日志就可看出。日志如下:

复制代码
xxx@ubuntu:~/myimage$ docker build -t imageb .
Sending build context to Docker daemon 15.87 kB
Step 1 : FROM imagea
# Executing 1 build trigger...
Step 1 : RUN mkdir mydir
 ---> Running in e16c35c94b03
 ---> 4b393d1610a6
Removing intermediate container e16c35c94b03
Step 2 : MAINTAINER hello1
 ---> Running in c7b0312516ea
 ---> 0f63b8e04d82
Removing intermediate container c7b0312516ea
Successfully built 0f63b8e04d82
复制代码

我们可以看出,FROM指令执行之后,就立即执行的是触发器(ONBUILD指令指定的指令)

 

VOLUME:

在介绍VOLUME指令之前,我们来看下如下场景需求:

1)容器是基于镜像创建的,最后的容器文件系统包括镜像的只读层+可写层,容器中的进程操作的数据持久化都是保存在容器的可写层上。一旦容器删除 后,这些数据就没了,除非我们人工备份下来(或者基于容器创建新的镜像)。能否可以让容器进程持久化的数据保存在主机上呢?这样即使容器删除了,数据还 在。

2)当我们在开发一个web应用时,开发环境是在主机本地,但运行测试环境是放在docker容器上。

这样的话,我在主机上修改文件(如html,js等)后,需要再同步到容器中。这显然比较麻烦。

3)多个容器运行一组相关联的服务,如果他们要共享一些数据怎么办?

对于这些问题,我们当然能想到各种解决方案。而docker本身提供了一种机制,可以将主机上的某个目录与容器的某个目录(称为挂载点、或者叫卷) 关联起来,容器上的挂载点下的内容就是主机的这个目录下的内容,这类似linux系统下mount的机制。 这样的话,我们修改主机上该目录的内容时,不需要同步容器,对容器来说是立即生效的。 挂载点可以让多个容器共享。

下面我们来介绍具体的机制。

一、通过docker run命令

1、运行命令:docker run --name test -it -v /home/xqh/myimage:/data ubuntu /bin/bash

其中的 -v 标记 在容器中设置了一个挂载点 /data(就是容器中的一个目录),并将主机上的 /home/xqh/myimage 目录中的内容关联到 /data下。

这样在容器中对/data目录下的操作,还是在主机上对/home/xqh/myimage的操作,都是完全实时同步的,因为这两个目录实际都是指向主机目录。

2、运行命令:docker run --name test1 -it -v /data ubuntu /bin/bash

上面-v的标记只设置了容器的挂载点,并没有指定关联的主机目录。这时docker会自动绑定主机上的一个目录。通过docker inspect 命令可以查看到。

复制代码
xqh@ubuntu:~/myimage$ docker inspect test1
[
{
    "Id": "1fd6c2c4bc545163d8c5c5b02d60052ea41900a781a82c20a8f02059cb82c30c",
.............................
    "Mounts": [
        {
            "Name": "0ab0aaf0d6ef391cb68b72bd8c43216a8f8ae9205f0ae941ef16ebe32dc9fc01",
            "Source": "/var/lib/docker/volumes/0ab0aaf0d6ef391cb68b72bd8c43216a8f8ae9205f0ae941ef16ebe32dc9fc01/_data",
            "Destination": "/data",
            "Driver": "local",
            "Mode": "",
            "RW": true
        }
    ],
...........................
复制代码

上面 Mounts下的每条信息记录了容器上一个挂载点的信息,"Destination" 值是容器的挂载点,"Source"值是对应的主机目录。

可以看出这种方式对应的主机目录是自动创建的,其目的不是让在主机上修改,而是让多个容器共享。

 

二、通过dockerfile创建挂载点

上面介绍的通过docker run命令的-v标识创建的挂载点只能对创建的容器有效。

通过dockerfile的 VOLUME 指令可以在镜像中创建挂载点,这样只要通过该镜像创建的容器都有了挂载点。

还有一个区别是,通过 VOLUME 指令创建的挂载点,无法指定主机上对应的目录,是自动生成的。

#test
FROM ubuntu
MAINTAINER hello1
VOLUME ["/data1","/data2"]

上面的dockfile文件通过VOLUME指令指定了两个挂载点 /data1 和 /data2.

我们通过docker inspect 查看通过该dockerfile创建的镜像生成的容器,可以看到如下信息

 

复制代码
    "Mounts": [
        {
            "Name": "d411f6b8f17f4418629d4e5a1ab69679dee369b39e13bb68bed77aa4a0d12d21",
            "Source": "/var/lib/docker/volumes/d411f6b8f17f4418629d4e5a1ab69679dee369b39e13bb68bed77aa4a0d12d21/_data",
            "Destination": "/data1",
            "Driver": "local",
            "Mode": "",
            "RW": true
        },
        {
            "Name": "6d3badcf47c4ac5955deda6f6ae56f4aaf1037a871275f46220c14ebd762fc36",
            "Source": "/var/lib/docker/volumes/6d3badcf47c4ac5955deda6f6ae56f4aaf1037a871275f46220c14ebd762fc36/_data",
            "Destination": "/data2",
            "Driver": "local",
            "Mode": "",
            "RW": true
        }
    ],
复制代码

可以看到两个挂载点的信息。

三、容器共享卷(挂载点)

docker run --name test1 -it myimage /bin/bash

上面命令中的 myimage是用前面的dockerfile文件构建的镜像。 这样容器test1就有了 /data1 和 /data2两个挂载点。

下面我们创建另一个容器可以和test1共享 /data1 和 /data2卷 ,这是在 docker run中使用 --volumes-from标记,如:

可以是来源不同镜像,如:

docker run --name test2 -it --volumes-from test1  ubuntu  /bin/bash

也可以是同一镜像,如:

docker run --name test3 -it --volumes-from test1  myimage  /bin/bash

上面的三个容器 test1 , test2 , test3 均有 /data1 和 /data2 两个目录,且目录中内容是共享的,任何一个容器修改了内容,别的容器都能获取到。

 

四、最佳实践:数据容器

如果多个容器需要共享数据(如持久化数据库、配置文件或者数据文件等),可以考虑创建一个特定的数据容器,该容器有1个或多个卷。

其它容器通过--volumes-from 来共享这个数据容器的卷。

因为容器的卷本质上对应主机上的目录,所以这个数据容器也不需要启动。

如: docker run --name dbdata myimage echo "data container"

 

说明:有个卷,容器之间的数据共享比较方便,但也有很多问题需要解决,如权限控制、数据的备份、卷的删除等。这些内容后续文章介绍。

posted @ 2017-03-01 01:32  wq3435  阅读(1245)  评论(1编辑  收藏  举报