Docker 应用的容器化(一)


Docker的核心思想就是如何将应用整合到容器中,并且能在容器中实际运行。将应用整合到容器中并且运行起来的这个过程,称为“容器化”

简介

简介:容器能够简化应用的构建、部署和运行过程。完整的应用容器化过程主要分为以下几个步骤。

  1. 编写应用代码。
  2. 创建一个Dockerfile,其中包括当前应用的描述、依赖以及该如何运行这个应用。
  3. 对该Dockerfile执行docker image build命令。
  4. 等待Docker将应用程序构建到Docker镜像中。

一旦应用容器化完成(即应用被打包为一个Docker镜像),就能以镜像的形式交付并以容器的方式运行。

具体操作

配置一个apache2服务器

1.编写应用代码。

目录结构

ronie@ronie-virtual-machine:~/Desktop/docker$ ls
index
ronie@ronie-virtual-machine:~/Desktop/docker$ cd index && ls
background.jpg  index.css  index.html
ronie@ronie-virtual-machine:~/Desktop/docker/index$ 

HTML文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>search</title>
    <link rel="stylesheet" href="index.css">
</head>
<body>
<div class="box">
    <form action="">
        <p class="head">Search</p>
        <input id="text" type="text" placeholder="Type to search">
        <input type="button" value="Search" onclick="f()">
    </form>
</div>
</body>
<script language="JavaScript">
    function f() {
        var a = document.getElementById("text");
        console.log(a.innerText);
        if (a.value && f1(a)) {
            var url = "https://www.baidu.com/baidu?tn=monline_7_dg&ie=utf-8&wd=" + a.value;
            window.open(url, '_blank');
            a.value = "";
        }
    }
    function f1(a) {
        for (var i = 0; i<(a.value).length; i++){
            if (a.value[i] !== " "){
                return true;
            }
        }
        return false;
    }
</script>
</html>

index.css文件

*{
    padding: 0;
    margin: 0;
}

body{
    background: url("background.jpg");
    background-size: cover;
    font-family: Georgia, serif;
}

.head{
    font-size: 26px;
    color: white;
}
.box{
    width: 500px;
    left: 50%;
    top: 50%;
    position: absolute;
    transform: translate(-50%, -50%);
}

input{
    position: relative;
    display: inline-block;
    font-size: 20px;
    box-sizing: border-box;
    transition: 1s;
    font-family: Georgia, serif;
}

input[type="text"]{
    background: #fff;
    width: 340px;
    height: 50px;
    border: none;
    outline: none;
    padding: 0 25px;
    border-radius: 25px 0 0 25px;
}
input[type="button"]{
    position: relative;
    width: 150px;
    left: -5px;
    height: 50px;
    border: none;
    outline: none;
    border-radius: 0 25px 25px 0;
    background-color: #ffa955;
    color: white;
}

input[type="button"]:hover{
    background-color: #a64044;
}

2.编写Dockfile

在代码目录当中,应当有个名称为Dockerfile的文件。这个文件包含了对当前应用的描述,并且能指导Docker完成镜像的构建。在Docker当中,包含应用文件的目录通常被称为构建上下文(Build Context)。通常将Dockerfile放到构建上下文的根目录下。

ronie@ronie-virtual-machine:~/Desktop/docker/index$ cd ..
ronie@ronie-virtual-machine:~/Desktop/docker$ touch Dockerfile
ronie@ronie-virtual-machine:~/Desktop/docker$ ls
Dockerfile  index
ronie@ronie-virtual-machine:~/Desktop/docker$ 

编写Dockerfile

from ubuntu:latest
label maintainer="ren_ronie@163.com"
run apt update && apt install nginx -y
workdir /var/www/html
copy ./index ./
expose 80
cmd ["nginx","-g","daemon off;"]                           
  • from ubuntu:latest:每个Dockerfile文件第一行都是FROM指令。FROM指令指定的镜像,会作为当前镜像的一个基础镜像层,当前应用的剩余内容会作为新增镜像层添加到基础镜像层之上。
  • label maintainer="ren_ronie@163.com":Dockerfile中通过标签(LABEL)方式指定了当前镜像的维护者。每个标签其实是一个键值对(Key-Value),在一个镜像当中可以通过增加标签的方式来为镜像添加自定义元数据。
  • run apt update && apt install nginx -y指令使用ubuntu的apt包管理器将nginx安装到当前镜像之中。RUN指令会在FROM指定的alpine基础镜像之上,新建一个镜像层来存储这些安装内容。
  • workdir /var/www/html:Dockerfile通过WORKDIR指令,为Dockerfile中尚未执行的指令设置工作目录。该目录与镜像相关,并且会作为元数据记录到镜像配置中,但不会创建新的镜像层。
  • copy ./index ./:COPY指令将应用相关文件从构建上下文复制到了当前镜像中,并且新建一个镜像层来存储。
  • expose 80:Dockerfile中通过EXPOSE指令来完成相应端口的设置。这个配置信息会作为镜像的元数据被保存下来,并不会产生新的镜像层。
  • cmd ["nginx","-g","daemon off;"]:CMD指令用于指定默认的容器主进程的启动命令。注意不应写为cmd ["service","nginx","start"],这样写容器执行后就立即退出了。甚至在容器内去使用systemctl命令结果却发现根本执行不了。这是因为没有搞明白前台、后台的概念,没有区分容器和虚拟机的差异,依旧在以传统虚拟机的角度去理解容器。对于容器而言,其启动程序就是容器应用进程,容器就是为了主进程而存在的,主进程退出,容器就失去了存在的意义,从而退出,其它辅助进程不是它需要关心的东西。使用 service nginx start命令,则是希望以后台守护进程形式启动nginx服务。而刚才说的CMD service nginx start会被理解为CMD [ "sh", "-c", "service nginx start"]

构建镜像
此命令会构建并生成一个名为ubuntu:nginx的镜像sudo docker build -t ubuntu:nginx .。最后应当包含这个点,并且在执行命令前,读者要确认当前目录是Dockerfile和应用代码的目录。以下是部分输出。

······
Step 4/7 : workdir /var/www/html
 ---> Running in b990a62993fe
Removing intermediate container b990a62993fe
 ---> 9e5173d5eaf8
Step 5/7 : copy ./index ./
 ---> 83e84e578b1f
Step 6/7 : expose 80
 ---> Running in cecbca81c334
Removing intermediate container cecbca81c334
 ---> e66486637863
Step 7/7 : cmd ["nginx","-g","daemon off;"]
 ---> Running in 06f44223e02e
Removing intermediate container 06f44223e02e
 ---> 241b51dea4a8
Successfully built 241b51dea4a8
Successfully tagged ubuntu:nginx

检查本地缓存中是否包含了ubuntu:nginx镜像,可以发现应用容器化已经成功了。

ronie@ronie-virtual-machine:~/Desktop/docker$ sudo docker image ls
REPOSITORY      TAG       IMAGE ID       CREATED         SIZE
ubuntu          nginx     241b51dea4a8   2 hours ago     171MB
python          latest    e285995a3494   5 days ago      921MB
ubuntu          latest    2dc39ba059dc   2 weeks ago     77.8MB
hello-world     latest    feb5d9fea6a5   12 months ago   13.3kB
80x86/typecho   latest    3437f7346b4c   3 years ago     53.9MB

启动容器
sudo docker container run -dit --name nginx -p 8080:80 ubuntu:nginx命令会基于web:latest这个镜像,启动一个名为nginx的容器。该容器将内部的80端口与Docker主机的8080端口进行映射。这意味可以打开一个浏览器,在地址栏输入Docker主机的DNS名称或者IP地址,然后就能直接访问这个Web应用。-d参数的作用是让应用程序以守护线程的方式在后台运行。-p 8080:80参数的作用是将主机的8080端口与容器内的80端口进行映射。

注意的问题

  • 使用docker container ls指令来确认容器已经启动并且正常运行。容器名称是nginx,并且从输出内容中能看到0.0.0.0:8080->80/tcp。
  • 确认防火墙或者其他网络安全设置没有阻止访问Docker主机的80端口。

总结

我们可以通过docker image history命令来查看在构建镜像的过程中都执行了哪些指令。每行内容都对应了Dockerfile中的一条指令(顺序是自下而上)。CREATE BY这一列中还展示了当前行具体对应Dockerfile中的哪条指令。

ronie@ronie-virtual-machine:~/Desktop/docker$ sudo docker image history ubuntu:nginx
IMAGE          CREATED       CREATED BY                                      SIZE      COMMENT
241b51dea4a8   2 hours ago   /bin/sh -c #(nop)  CMD ["nginx" "-g" "daemon…   0B        
e66486637863   2 hours ago   /bin/sh -c #(nop)  EXPOSE 80                    0B        
83e84e578b1f   2 hours ago   /bin/sh -c #(nop) COPY dir:71ce577139b3b3b62…   406kB     
9e5173d5eaf8   2 hours ago   /bin/sh -c #(nop) WORKDIR /var/www/html         0B        
a1f1237a76d1   2 hours ago   /bin/sh -c apt update && apt install nginx -y   92.7MB    
8850173b91ee   3 hours ago   /bin/sh -c #(nop)  LABEL maintainer=ren_roni…   0B        
2dc39ba059dc   2 weeks ago   /bin/sh -c #(nop)  CMD ["bash"]                 0B        
<missing>      2 weeks ago   /bin/sh -c #(nop) ADD file:a7268f82a86219801…   77.8MB

我们可以注意到只有三个层被创建了,我们可以在通过docker image inspect命令来查看镜像的具体信息。(只截取了关注的部分)

  "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:7f5cbd8cc787c8d628630756bcc7240e6c96b876c2882e6fc980a8b60cdfa274",
                "sha256:f756c593d529327421a0f3ef6700c5de331d065f3308359c7fb777f23e45adc0",
                "sha256:fced763bdc454d1f2a68e16d90dd04cca12b83773c32d73265ab3f58ae56c20d"
            ]
        },

声明:Hello World|版权所有,违者必究|如未注明,均为原创|本网站采用BY-NC-SA协议进行授权

转载:转载请注明原文链接 - Docker 应用的容器化(一)


我的朋友,理论是灰色的,而生活之树是常青的!