通过Dockerfile创建镜像
Docker 提供了一种更便捷的方式,叫作 Dockerfile
docker build命令用于根据给定的Dockerfile构建Docker镜像。
docker build语法:
# docker build [OPTIONS] <PATH | URL | ->
1. 常用选项说明 --build-arg,设置构建时的变量 --no-cache,默认false。设置该选项,将不使用Build Cache构建镜像 --pull,默认false。设置该选项,总是尝试pull镜像的最新版本 --compress,默认false。设置该选项,将使用gzip压缩构建的上下文 --disable-content-trust,默认true。设置该选项,将对镜像进行验证 --file, -f,Dockerfile的完整路径,默认值为‘PATH/Dockerfile’ --isolation,默认--isolation="default",即Linux命名空间;其他还有process或hyperv --label,为生成的镜像设置metadata --squash,默认false。设置该选项,将新构建出的多个层压缩为一个新层,但是将无法在多个镜像之间共享新层;设置该选项,实际上是创建了新image,同时保留原有image。 --tag, -t,镜像的名字及tag,通常name:tag或者name格式;可以在一次构建中为一个镜像设置多个tag --network,默认default。设置该选项,Set the networking mode for the RUN instructions during build --quiet, -q ,默认false。设置该选项,Suppress the build output and print image ID on success --force-rm,默认false。设置该选项,总是删除掉中间环节的容器 --rm,默认--rm=true,即整个构建过程成功后删除中间环节的容器
示例: docker build -t soso/bbauto:v2.1 . docker build 是docker创建镜像的命令 -t 是标识新建的镜像属于 soso的 bbauto镜像 :v2 是tag "."是用来指明 我们的使用的Dockerfile文件当前目录的
2.1、 创建镜像所在的文件夹和Dockerfile文件
[root@yixuan ~]# mkdir sinatra [root@yixuan ~]# cd sinatra/ [root@yixuan sinatra]# touch Dockerfile
2.2、 在Dockerfile文件中写入指令,每一条指令都会更新镜像的信息例如:
[root@yixuan sinatra]# vim Dockerfile #This is a comment FROM daocloud.io/library/centos:7 MAINTAINER soso soso@yixuan RUN yum install -y wget RUN touch a.txt RUN mkdir /test
格式说明:
命令要大写,"#"是注解。 每一个指令后面需要跟空格,语法。 FROM 命令是告诉docker 我们的镜像什么从哪里下载。 MAINTAINER 是描述 镜像的创建人。 maintainer RUN 命令是在镜像内部执行。就是说他后面的命令应该是针对镜像可以运行的命令。
2.3、创建镜像
命令: # docker build -t soso/centso:7 . docker build 是docker创建镜像的命令
详细执行过程:
[root@yixuan sinatra]# docker build -t soso/centos:7 . Sending build context to Docker daemon 2.048kB Step 1/4 : FROM daocloud.io/library/centos latest: Pulling from library/centos d8d02d457314: Pull complete Digest: sha256:a36b9e68613d07eec4ef553da84d0012a5ca5ae4a830cf825bb68b929475c869 Status: Downloaded newer image for daocloud.io/library/centos:latest ---> 67fa590cfc1c Step 2/4 : MAINTAINER soso soso@yixuan ---> Running in aab3d80939d8 Removing intermediate container aab3d80939d8 ---> 12bae7d75a23 Step 3/4 : RUN yum update && yum install -y epel* ---> Running in ad83c387c60f Loaded plugins: fastestmirror, ovl Determining fastest mirrors * base: mirrors.aliyun.com * extras: mirrors.aliyun.com * updates: mirrors.aliyun.com Resolving Dependencies --> Running transaction check ---> Package audit-libs.x86_64 0:2.8.4-4.el7 will be updated ---> Package audit-libs.x86_64 0:2.8.5-4.el7 will be an update
2.4、创建完成后,从镜像创建容器
Dockerfile实例:容器化python的flask应用
目标: 用 Docker 部署一个用 Python 编写的 Web 应用。
首先部署整个流程:
基础镜像(python)-->flask-->部署python应用 web框架 flask django
代码功能:
如果当前环境中有"NAME"这个环境变量,就把它打印在"Hello"后,否则就打印"Hello world",最后再打印出当前环境的 hostname。
[root@yixuan ~]# mkdir python_app [root@yixuan ~]# cd python_app/ [root@yixuan python_app]# vim app.py from flask import Flask import socket import os app = Flask(__name__) @app.route('/') def hello(): html = "<h3>Hello {name}!</h3>" \ "<b>Hostname:</b> {hostname}<br/>" return html.format(name=os.getenv("NAME", "world"), hostname=socket.gethostname()) if __name__ == "__main__": app.run(host='0.0.0.0', port=80)
应用依赖:
定义在同目录下的 requirements.txt 文件里,内容如下:
[root@yixuan python_app]# vim requirements.txt Flask
Dockerfile制作容器镜像:
# vim Dockerfile FROM python:2.7-slim WORKDIR /app ADD . /app RUN pip install --trusted-host [pypi.python.org|mirrors.aliyun.com] -r requirements.txt EXPOSE 80 ENV NAME World CMD ["python", "app.py"]
Dockerfile文件说明:
FROM python:2.7-slim # 使用官方提供的 Python 开发镜像作为基础镜像 # 指定"python:2.7-slim"这个官方维护的基础镜像,从而免去安装 Python 等语言环境的操作。: WORKDIR /app # 将工作目录切换为 /app,意思是在这一句之后,Dockerfile 后面的操作都以这一句指定的 /app 目录作为当前目录。 ADD . /app # 将当前目录下的所有内容复制到 /app 下 Dockerfile 里的原语并不都是指对容器内部的操作。比如 ADD,指的是把当前目录(即 Dockerfile 所在的目录)里的文件,复制到指定容器内的目录当中。 RUN pip install --trusted-host pypi.python.org -r requirements.txt # 使用 pip 命令安装这个应用所需要的依赖 EXPOSE 80 # 允许外界访问容器的 80 端口 ENV NAME World # 设置环境变量 CMD ["python", "app.py"] # 设置容器进程为:python app.py,即:这个 Python 应用的启动命令,这里app.py 的实际路径是 /app/app.py。CMD ["python", "app.py"] 等价于 "docker run python app.py"。
现在目录结构:
[root@yixuan python_app]# ls Dockerfile app.py requirements.txt
构建镜像:
[root@yixuan python_app]# docker build -t testpython . -t 给这个镜像加一个 Tag
Dockerfile 中的每个原语执行后,都会生成一个对应的镜像层。即使原语本身并没有明显地修改文件的操作(比如,ENV 原语),它对应的层也会存在。只不过在外界看来,这个层是空的。
查看结果:
[root@yixuan python_app]# docker images REPOSITORY TAG IMAGE ID ... testpython latest 16bc21f3eea3
启动容器:
[root@yixuan python_app]# docker run -it -p 4000:80 testpython /bin/bash
查看容器:
[root@yixuan python_app]# docker ps CONTAINER ID IMAGE COMMAND CREATED ce02568e64ce testpython "/bin/bash" About a minute ago
进入容器:
[root@yixuan python_app]# docker exec -it ce02568 /bin/bash root@ce02568e64ce:/app# python app.py & #将python运行起来
访问容器内应用:
[root@yixuan ~]# curl http://localhost:4000 <h3>Hello World!</h3><b>Hostname:</b> f201f6855136<br/>
实战练习
1.创建一个nginx的dockerfile [root@yixuan ~]# mkdir nginx [root@yixuan ~]# cd nginx/ [root@yixuan nginx]# vim Dockerfile # This my first nginx Dockerfile # Version 1.0 FROM daocloud.io/library/centos:7 MAINTAINER yixuan ENV PATH /usr/local/nginx/sbin:$PATH ADD nginx-1.16.1.tar.gz /usr/local/ ADD epel-release-7-11.noarch.rpm /usr/local/ RUN rpm -ivh /usr/local/epel-release-7-11.noarch.rpm RUN yum install -y gcc gcc-c++ make && yum -y install openssl openssl-devel && yum install -y zlib zlib-devel && yum clean all RUN useradd -s /sbin/nologin -M www WORKDIR /usr/local/nginx-1.16.1 RUN ./configure --prefix=/usr/local/nginx --user=www --group=www && make && make install RUN echo "daemon off;" >> /etc/nginx.conf EXPOSE 80 CMD /bin/sh -c 'nginx -g "daemon off;"' #放前台启动 [root@yixuan nginx]# ls #将nginx的tar包与epel源上传到nginx目录下面 Dockerfile epel-release-7-11.noarch.rpm nginx-1.16.1.tar.gz [root@yixuan nginx]# pwd /root/nginx [root@yixuan nginx]# docker build -t nginx:v7.1 . [root@yixuan nginx]# docker run -itd --name nginx9 -p 8088:80 nginx:v7.1 #启动容器 [root@yixuan nginx]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES fec1f3a37cb0 nginx:v7.1 "/bin/sh -c '/bin/sh…" 6 seconds ago Up 5 seconds 0.0.0.0:8088->80/tcp
2.创建一个jenkins的Dockerfile [root@yixuan ~]# mkdir tomcat [root@yixuan ~]# cd tomcat/ [root@yixuan tomcat]# vim Dockerfile # This my first jenkins Dockerfile # Version 1.0 FROM daocloud.io/library/centos:7 MAINTAINER yixuan ENV JAVA_HOME /usr/local/jdk1.8.0_211 ENV TOMCAT_HOME /usr/local/apache-tomcat-8.5.47 ENV PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH ENV CLASSPATH=.:$JAVA_HOME/lib:$JAVA_HOME/jre/lib:$JAVA_HOME/lib/tools.jar ADD apache-tomcat-8.5.47.tar.gz /usr/local/ ADD jdk-8u211-linux-x64.tar.gz /usr/local/ RUN rm -rf /usr/local/apache-tomcat-8.5.47/webapps/* ADD jenkins.war /usr/local/apache-tomcat-8.5.47/webapps RUN rm -rf apache-tomcat-8.5.47.tar.gz apache-tomcat-8.5.47.tar.gz EXPOSE 8080 ENTRYPOINT ["/usr/local/apache-tomcat-8.5.47/bin/catalina.sh","run"] #运行的命令 [root@yixuan tomcat]# pwd /root/tomcat [root@yixuan tomcat]# ls #将jdk与tomcat还有jenkins的包上传到tomcat目录中 apache-tomcat-8.5.47.tar.gz Dockerfile jdk-8u211-linux-x64.tar.gz jenkins.war [root@yixuan tomcat]# docker build -t jenkins:v1 . [root@yixuan tomcat]# docker run -itd --name jenkins1 -p 8081:8080 jenkins:v1
3.创建一个jenkins的Dockerfile FROM centos:7 LABEL maintainer="qingning" ADD https://pkg.jenkins.io/redhat-stable/jenkins.repo /etc/yum.repos.d/jenkins.repo RUN rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io-2023.key &&\ yum -y install fontconfig &&\ yum -y install https://download.oracle.com/java/17/latest/jdk-17_linux-x64_bin.rpm &&\ yum -y install jenkins && \ yum clean all CMD jenkins
镜像已构建完成,并上传至hub.docker.com/qingning800/jenkins:2.1
扩展----CMD与ENTRYPOINT区别
一、dockerfile中的 CMD 1、每个dockerfile中只能有一个CMD如果有多个那么只执行最后一个。 2、CMD 相当于启动docker时候后面添加的参数看,举个简单例子: # docker run -itd --name test image(镜像) /bin/bash -c a、镜像名称后面跟了一个/bin/bash -c ,其实等价于在dockerfile中的CMD ["/bin/bash","-c"]。 b、如果dockerfile中的CMD中有了CMD["/bin/bash","-c"],那么就不用在执行的时候再添加了,如果添加了参数的话那么就相当于要执行你添加的参数,默认的CMD中的参数就无效了。 二、dockerfile中的ENTRYPOINT 1、一个dockerfile中ENTRYPOINT也只能存在一个,若存在多个那么只执行最后一个,你可以理解为开机启动的意思,和CMD有点像,不过还是有区别。 2、举个简单例子: a、dockerfile中有ENTRYPOINT ["tail","-f","/var/log/nginx/access.log"],那么启动的时候镜像就执行了这个里面的内容,如果你像上面带参数的话就相当于在这个执行的内容后面再加入参数。 案例: 如果我们的dockerfile中有a中的这句话然后我们启动我们的docker: #docker run -itd --name test image(镜像名) /bin/bash -c 此时就相当于我们启动docker的时候执行了:tail -f /var/log/nginx/access.log /bin/bash -c 这个命令明显就不对.
FROM centos:7 CMD ["ls","-a"] ENTRYPOINT ["ls","-a"] 加参数 -l测试