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"
说明:有个卷,容器之间的数据共享比较方便,但也有很多问题需要解决,如权限控制、数据的备份、卷的删除等。这些内容后续文章介绍。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步