同福

使用Dockerfile创建Docker镜像【20210509】

介绍

介绍

在微服务的时代学会使用Docker是必须的,在Docker里面应用是部署在容器(Container)里的,而创建容器就需要镜像(Image),得到镜像的方法有两种。一种是通过拉取centos基础镜像,在里面进行安装配置,最后打包成新的镜像使用;另外一种就是直接在Docker云里拉取人家安装配置好的镜像,然后通过Dockerfile把自己的配置参数加入进去,最后打包成新的镜像使用。

相比之下,第二种方法更加简单,因为知识我们不需要去找应用的官网,下载合适的版本,安装各种依赖库,安装各种辅助工具,解决各种兼容问题了,只需要考虑我们该考虑的问题即可!

今天福哥将带着大家学习如何使用Dockerfile创建Docker镜像,大家跟着来吧!

设计

要注意一个问题,我们选择第二种方式创建镜像是基于我们要搭建微服务的,如果你喜欢在一个容器里面安装各种各样的应用的话,那么还是采用第一种方式吧。

基础镜像

前面说过了,第二种方法是在别人的安装配置好的镜像基础之上进行参数调整的,所以首先我们得知道如何找到别人安装配置好的镜像。

镜像搜索

在Docker云里面有着无数多的大神弄好的镜像,我们可以通过search命令进行搜索,基本上我们想要的应用都可以找到不止一个基础镜像。例如:我们想安装一个nginx服务,就可以执行下面的命令搜索。

docker search nginx

home/topic/2021/0507/16/9f0041a59fdf3b9f8a0b8528effeb85f.jpg

拉取镜像

注意INDEX列和NAME列,INDEX为docker.io的就是官方镜像库,NAME就是完整的镜像地址。选择好了基础镜像之后就可以通过“pull”命令拉取下来了。例如:福哥拉取了“docker.io/nginx”这个镜像。

docker pull docker.io/nginx

home/topic/2021/0507/16/0f3c4a9ccce2d7d5010384ae830424f0.jpg不过,我们今天要学习的是通过Dockerfile来创建镜像,也就是说我们不需要单独地拉取镜像下来,这些都会在后面的Dockerfile脚本里面自动完成的了。

Dockerfile

其实Dockerfile就是一个脚本,Docker会根据我们编写的Dockerfile脚本完成一系列的自动部署操作,最后将最终的状态生成一个镜像。

FROM

FROM命令用来指定基础镜像,我们不能凭空建立一个系统环境,需要在某个已经存在的镜像基础之上创建新的镜像。

FROM docker.io/nginx

RUN

RUN命令可以执行Shell命令,我们可以通过Shell命令完成我们想要的部署操作。

RUN yum install wget

MAINTAINER

MAINTAINER命令用来设置作者的信息。

MAINTAINER Andy Bogate <tongfu@tongfu.net>

ADD

ADD命令可以将本地的文件打包到镜像里面,支持通配符。

如果需要把目录打包到镜像里面,可以先将目录打包到一个tar压缩包里面,然后添加这个压缩包。

ADD tfums_server.conf /etc/nginx/conf.d/

COPY

COPY命令可以将本地的文件打包到镜像里面,不会对tar压缩包进行解压缩。

COPY tfphp-1.0.0-utf-8.tar /data/web/download/

CMD

CMD命令指定的命令会在容器启动时候执行,类似rc.local的作用,但是更好用。

CMD /etc/start_service.sh

ENTRYPOINT

ENTRYPOINT命令就是运行容器的时候第一次要执行的命令,一个Dockerfile里面只能有一个ENTRYPOINT命令,设置了多个的话最后一个生效。

ENTRYPOINT /etc/start_service.sh

LABEL

LABEL命令可以为镜像添加元数据。

LABEL name="福哥" age="35"

ENV

ENV命令可以为镜像添加环境变量,变量在创建镜像的时候,或者镜像被用来启动容器后都是有效的。

可以在docker run时候通过-e设置ENV环境变量。

可以在docker-compose的environment里设置ENV环境变量。

设置ENV环境变量。

设置两个环境变量id和name。

ENV id 35
ENV name 福哥

引用ENV环境变量。

在Dockerfile里面设置启用脚本为/root/start.sh,在/root/start.sh里面调用环境变量id和name。

Dockerfile

ENTRYPOINT ["/root/start.sh"]

/root/start.sh

#!/bin/sh

echo "name: ${name}" > /etc/userinfo/$id

EXPOSE

EXPOSE命令用来指定容器暴露出去的端口。

EXPOSE 80

VOLUME

VOLUME命令用来指定持久化目录。

VOLUME /var/log/mysql

WORKDIR

WORKDIR命令用来在Dockerfile执行期间切换“当前目录”使用。镜像被用来启动容器后会切换到WORKDIR目录下面。

WORKDIR /etc/nginx/conf.d/

USER

USER命令用来指定容器的用户。

USER webadmin

ARG

ARG命令用来设置创建镜像时候的参数。

ARG参数只在创建镜像的过程中有效,且不能通过外部环境传入。

设置ARG参数。

ARG id=35
ARG name=福哥

引用ARG参数。

RUN echo "name: ${name}" > /tmp/userinfo/$id

ONBUILD

ONBUILD命令可以在别人用我们创建的新镜像去二次创建镜像的时候自动触发执行的命令。

ONBUILD RUN rm -f /etc/.secret_key

创建镜像

编辑好Dockerfile脚本,就可以通过如下的命令创建我们想要的镜像了。

  • 通过“-f”参数指定Dockerfile路径

  • 通过“-t”参数设置新的镜像的名称

  • 最后是创建新的镜像的根目录,根目录下面的内容会被发送到Docker云,要特别注意一下哦~~

docker build -f Dockerfile -t tfums_nginx ./

Nginx示例

现在我们打包一个基于docker.io/nginx的镜像,把里面的默认配置文件替换掉。

基础镜像

我们如果都不知道基础镜像的系统结构,就不用谈去修改它了。所以,先拉取基础镜像下来,启动一个临时容器,切进去看看。

创建临时容器

[root@dev ~]# docker run -tid --name tfums_nginx -h tfums_nginx --net bridge2 --ip 10.16.1.100 docker.io/nginx
2eb122a5d394f21db69ba478cb2cd57071ce1891654d237f780310aaa342902e

切入临时容器

[root@dev ~]# docker exec -it tfums_nginx "/bin/bash"

搜索nginx相关

root@tfums_nginx:/# find / -iname "*nginx*"
/etc/rc5.d/S01nginx
/etc/rc6.d/K01nginx
/etc/logrotate.d/nginx
/etc/init.d/nginx-debug
/etc/init.d/nginx
/etc/default/nginx-debug
/etc/default/nginx
/etc/systemd/system/multi-user.target.wants/nginx.service
/etc/rc0.d/K01nginx
/etc/rc1.d/K01nginx
/etc/rc2.d/S01nginx
/etc/rc3.d/S01nginx
/etc/rc4.d/S01nginx
/etc/nginx
/etc/nginx/nginx.conf
/usr/lib/nginx
/usr/sbin/nginx-debug
/usr/sbin/nginx
/usr/share/doc/nginx-module-xslt
/usr/share/doc/nginx-module-geoip
/usr/share/doc/nginx-module-image-filter
/usr/share/doc/nginx
/usr/share/doc/nginx-module-njs
/usr/share/nginx
/var/lib/dpkg/info/nginx-module-image-filter.list
/var/lib/dpkg/info/nginx-module-image-filter.md5sums
/var/lib/dpkg/info/nginx.postinst
/var/lib/dpkg/info/nginx-module-geoip.list
/var/lib/dpkg/info/nginx.md5sums
/var/lib/dpkg/info/nginx-module-njs.list
/var/lib/dpkg/info/nginx-module-njs.postinst
/var/lib/dpkg/info/nginx-module-image-filter.postinst
/var/lib/dpkg/info/nginx-module-geoip.postinst
/var/lib/dpkg/info/nginx-module-xslt.list
/var/lib/dpkg/info/nginx-module-njs.md5sums
/var/lib/dpkg/info/nginx.list
/var/lib/dpkg/info/nginx-module-xslt.md5sums
/var/lib/dpkg/info/nginx-module-xslt.postinst
/var/lib/dpkg/info/nginx.postrm
/var/lib/dpkg/info/nginx.prerm
/var/lib/dpkg/info/nginx-module-geoip.md5sums
/var/lib/dpkg/info/nginx.preinst
/var/lib/dpkg/info/nginx.conffiles
/var/lib/systemd/deb-systemd-helper-enabled/multi-user.target.wants/nginx.service
/var/lib/systemd/deb-systemd-helper-enabled/nginx.service.dsh-also
/var/lib/systemd/deb-systemd-helper-enabled/nginx-debug.service.dsh-also
/var/cache/nginx
/var/log/nginx
/lib/systemd/system/nginx.service
/lib/systemd/system/nginx-debug.service
/run/nginx.pid
find: '/proc/1/map_files': Operation not permitted
find: '/proc/30/map_files': Operation not permitted
find: '/proc/31/map_files': Operation not permitted
find: '/proc/36/map_files': Operation not permitted

可以看到我们搜索到了几个比较重要的内容,包括配置文件和启动脚本,这里面我们只需要替换配置文件即可。

/etc/nginx/nginx.conf

查看nginx.conf

打开nginx.conf,发现真正的配置文件都在/etc/nginx/conf.d/下面。

root@tfums_nginx:/# cat /etc/nginx/nginx.conf 

user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;
}

查看default.conf

查看/etc/nginx/conf.d/目录,发现了唯一的默认配置文件default.conf,打开它看看。

root@tfums_nginx:/# ls /etc/nginx/conf.d/
default.conf
root@tfums_nginx:/# cat /etc/nginx/conf.d/default.conf 
server {
    listen       80;
    listen  [::]:80;
    server_name  localhost;

    #charset koi8-r;
    #access_log  /var/log/nginx/host.access.log  main;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    #error_page  404              /404.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    # proxy the PHP scripts to Apache listening on 127.0.0.1:80
    #
    #location ~ \.php$ {
    #    proxy_pass   http://127.0.0.1;
    #}

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    #location ~ \.php$ {
    #    root           html;
    #    fastcgi_pass   127.0.0.1:9000;
    #    fastcgi_index  index.php;
    #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
    #    include        fastcgi_params;
    #}

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    #location ~ /\.ht {
    #    deny  all;
    #}
}

在default.conf里是一个标准的nginx的server配置,没什么好说的了,反正等下福哥要替换它。

退出临时容器

root@tfums_nginx:/# exit
exit

删除临时容器

[root@dev ~]# docker stop tfums_nginx
tfums_nginx
[root@dev ~]# docker rm tfums_nginx
tfums_nginx

Dockerfile

现在我们开始编写Dockerfile脚本,基础镜像自然就是docker.io/nginx了。首先需要建立一个空目录,把新镜像需要的文件都放里面。

创建Dockerfile目录

福哥把Docker的镜像都放到了/docker.images下面了,而tfums_nginx是福哥给新的镜像起的名字。

[root@dev /]# cd /docker.images/
[root@dev docker.images]# mkdir tfums_nginx
[root@dev docker.images]# cd tfums_nginx/
[root@dev tfums_nginx]#

添加替换配置文件

大家可以看到,我将nignx的80端口上面的服务代理给同福网官网了。

[root@dev tfums_nginx]# cat tfums_server.conf 
server {
    listen       80;
    server_name  localhost;

    location / {
            proxy_pass              https://tongfu.net;
            proxy_set_header Host tongfu.net;
            proxy_set_header X-Real-Ip $remote_addr;
            proxy_set_header X-Forwarded-For $remote_addr;
    }
}

创建Dockerfile脚本

脚本很简单,说明一下:

  • 基于docker.io/nginx镜像创建

  • 复制tfums_server.conf到nginx配置文件目录下面

  • 删除默认的nginx配置文件。

[root@dev tfums_nginx]# cat Dockerfile 
FROM docker.io/nginx

ADD tfums_server.conf /etc/nginx/conf.d/
RUN rm -f /etc/nginx/conf.d/default.conf

创建新的镜像

使用build命令创建新的镜像,可以看到每一步都很清晰明白的运行了。

[root@dev tfums_nginx]# docker build -f Dockerfile -t tfums_nginx ./
Sending build context to Docker daemon 3.072 kB
Step 1/3 : FROM docker.io/nginx
 ---> 62d49f9bab67
Step 2/3 : ADD tfums_server.conf /etc/nginx/conf.d/
 ---> acd156efa1ce
Removing intermediate container 8249905578d5
Step 3/3 : RUN rm -f /etc/nginx/conf.d/default.conf
 ---> Running in 05fe00f656b2


 ---> c48e2f8da850
Removing intermediate container 05fe00f656b2
Successfully built c48e2f8da850

创建新的容器

使用新的镜像tfums_nginx创建容器。

[root@dev tfums_nginx]# docker run -tid --name tfums_nginx -h tfums_nginx --net bridge2 --ip 10.16.1.100 tfums_nginx
7e48b13e64a9117e8dddf384124c6644bb2b52d2f747dd68097c8ddca63f1d7e

测试新的容器

可以看到容器里面的nginx正在按照福哥的设计将同福网的官网首页代理过来了。

home/topic/2021/0507/18/ea3ae1f1fcdfb675e56136016cc6c85d.jpg

DockerHub

官方提供了一个网站,类似github那样的功能(连界面都基本一样),可以在上面搜索比较好的基础镜像。

官网地址

DockerHub的官网地址。

https://hub.docker.com/

搜索示例

这是一个搜索示例,很明显要比search命令强大太多太多了。

home/topic/2021/0507/19/fd955569851361c8a1b56593da5cd101.jpg

总结

今天童鞋们跟着福哥学会了如何使用Dockerfile创建镜像的方法,这其实是最简单的。如何把我们的传统网站或者平台拆分成若干的微服务还是需要比较经验老道的高手进行架构设计的,这个东西福哥会在后面带着大家对实现微服务架构的部署进行一个了解和学习的,敬请期待~~