Fork me on GitHub

构建docker镜像

一、基于容器生成镜像

基于容器生成镜像,实际上就是在某一个容器中添加一些功能,然后再生成新的镜像,例如下面这是linux上已经存在的镜像:

[vagrant@localhost ~]$ docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
centos              latest              470671670cac        10 days ago         237MB
hello-world         latest              fce289e99eb9        13 months ago       1.84kB

现在,在centos镜像的容器中添加vim功能然后生成新的镜像:

1、运行centos镜像

需要使用交互式的运行命令:

[vagrant@localhost ~]$ docker run -it centos
[root@68804cc4767f /]# 

2、安装vim

注意此时已经进入到容器内部,在容器内安装vim:

[root@68804cc4767f /]# yum install -y vim

3、查看容器

这样完成vim的安装,退出该容器,并且查看刚刚创建的容器:

[vagrant@localhost ~]$ docker container ls -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                      PORTS               NAMES
68804cc4767f        centos              "/bin/bash"         3 minutes ago       Exited (0) 21 seconds ago                       interesting_wu

4、提交容器

提交刚刚做过改变的容器,使其成为新的镜像:

[vagrant@localhost ~]$ docker commit interesting_wu shenjianping0307/centos-vim
sha256:731f454d1dd9420fed08eeec499285908d69d33541acc22b7eb4a454b4e9b9e8

#注意
#其中interesting_wu 为容器的Name
#centos-vim为镜像的名称

5、查看镜像

[vagrant@localhost ~]$ docker image ls
REPOSITORY                    TAG                 IMAGE ID            CREATED             SIZE
shenjianping0307/centos-vim   latest              731f454d1dd9        2 minutes ago       298MB
centos                        latest              470671670cac        10 days ago         237MB

6、基础镜像与新建镜像的比较

基础镜像是centos,自己制作的镜像的centos-vim,它们之间有什么区别呢?自己制作的镜像实际上就是在基础镜像的基础上添加了一层,也就是vim。

[vagrant@localhost ~]$ docker history 470671670cac  #base镜像layer
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
470671670cac        10 days ago         /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B                  
<missing>           10 days ago         /bin/sh -c #(nop)  LABEL org.label-schema.sc…   0B                  
<missing>           13 days ago         /bin/sh -c #(nop) ADD file:aa54047c80ba30064…   237MB      
         
[vagrant@localhost ~]$ docker history 731f454d1dd9  #新建镜像layer
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
731f454d1dd9        6 minutes ago       /bin/bash                                       60.4MB              
470671670cac        10 days ago         /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B                  
<missing>           10 days ago         /bin/sh -c #(nop)  LABEL org.label-schema.sc…   0B                  
<missing>           13 days ago         /bin/sh -c #(nop) ADD file:aa54047c80ba30064…   237MB   

二、基于Dockerfile生成镜像

(一)Dockerfile初体验

 首先先删掉之前创建的centos-vim镜像

[vagrant@localhost ~]$ docker image rm 731f454d1dd9
Untagged: shenjianping0307/centos-vim:latest
Deleted: sha256:731f454d1dd9420fed08eeec499285908d69d33541acc22b7eb4a454b4e9b9e8
Deleted: sha256:6626f7fa820cd657070d377576e7deda5e6285f949c506fb2c045735499989e3

1、创建Dockerfile文件

[vagrant@localhost ~]$ mkdir centos-vim    #创建文件夹
[vagrant@localhost ~]$ cd centos-vim/  #进入文件夹
[vagrant@localhost centos-vim]$ vim Dockerfile #编写Dockerfile

Dockerfile中的文件内容为:

FROM centos
RUN yum install -y vim

2、生成镜像

[vagrant@localhost centos-vim]$ docker build -t shenjianping0307/centos-vim .

#说明
#1、-t是tag标签的意思
#2、.表示在当前目录下执行Dockerfile

3、查看镜像

[vagrant@localhost centos-vim]$ docker image ls
REPOSITORY                    TAG                 IMAGE ID            CREATED             SIZE
shenjianping0307/centos-vim   latest              0a5f18d9f786        56 seconds ago      298MB
centos                        latest              470671670cac        10 days ago         237MB

(二)详解Dockerfile 

1、FROM

FROM关键字用于该镜像的基础镜像

FROM scratch   #不依赖于任何的基础镜像,从头开始
FROM centos   #依赖于centos基础镜像
FROM ubuntu:14.04 #依赖于指定版本的ubuntu的基础镜像

2、LABEL

对镜像的一些说明信息

LABEL maintainer "xxx@g.mail"  #作者信息
LABEL version = "1.0"  #版本信息
LABEL description = "This is description" #描述信息

3、RUN

执行的命令,每执行一次就会生成一层layer

RUN yum update && yum install -y vim \

#反斜线表示换行,无用分层,合并多条命令

4、WORKDIR

设定工作目录,类似于cd

WORKDIR /a  #如果没有会自动创建a目录
WORKDIR test
RUN pwd  #输出是/a/test

注意:尽量使用WORKDIR,避免使用RUN cd命令,尽量使用绝对目录。

5、ADD、COPY

这两个命令都是将本地文件加入到镜像中,那么它们的区别是什么呢?

ADD不仅可以将本地文件添加到镜像中,并且可以对文件进行解压,COPY是达不到这点的。

ADD t1.txt /   #将本地文件t1.txt添加到镜像根目录中
ADD t1.tar.gz #添加到根目录并且解压

WORKDIR /root
ADD t1 test/    #将t1添加至 /root/test/ 下

WORKDIR /root
COPY t1 test/    #将t1添加至 /root/test/ 下

大部分情况下,COPY由于ADD,除了ADD有解压缩的功能除外。ADD和COPY都是添加本地文件,如果获取远程文件,可通过RUN curl 或者RUN wget完成。

6、ENV

设置环境变量

ENV MYSQL_VERSION 5.6  #设置常量
RUN apt-get install -y mysql-server = "${MYSQL_VERSION}" \
&& rm -rf /var/lib/apt/lists/*  #引用常量

使用ENV利于维护性。

7、RUN、CMD、ENTRYPOINT

  • RUN 执行命令并创建新的Image Layer
  • CMD 设置容器启动后默认执行的命令和参数(如果docker run指定了其它命令,CMD命令被忽略;定义多个CMD,只会执行最后一个)
  • ENTRYPOINT 设置容器启动时运行的命令

在此之前需要说明一下Shell格式和EXec格式的命令

ENV MYSQL_VERSION 5.6  #设置常量
RUN apt-get install -y mysql-server = "${MYSQL_VERSION}" \
&& rm -rf /var/lib/apt/lists/*  #引用常量

Shell和Exec格式

Shell格式
RUN apt-get install -y vim
CMD echo "hello docker"
ENTRYPOINT echo "hello docker"

Exec格式
RUN ["apt-get", "install", "-y", "vim"]
CMD ["/bin/echo", "hello docker"]
ENTRYPOINT ["/bin/echo", "hello docker"]
View Code

这里分别以Shell格式和Exec格式命令来进行制作镜像

(1)Shell格式的Dockerfile

FROM centos
ENV name Docker
CMD echo "Hello $name"

然后进行制作镜像:

[vagrant@localhost test-command]$ docker build -t shenjianping0307/centos-cmd .
Sending build context to Docker daemon  2.048kB
Step 1/3 : FROM centos
 ---> 470671670cac
Step 2/3 : ENV name Docker
 ---> Running in 0a09ef3c9ff3
Removing intermediate container 0a09ef3c9ff3
 ---> e5aca6e78cba
Step 3/3 : CMD echo "Hello $name"
 ---> Running in bf73cf74e082
Removing intermediate container bf73cf74e082
 ---> 4f11efce0c70
Successfully built 4f11efce0c70
Successfully tagged shenjianping0307/centos-cmd:latest
View Code

显然执行这个镜像是可以成功的:

[vagrant@localhost test-command]$ docker run shenjianping0307/centos-cmd
Hello Docker

(2)Exec格式的Dockerfile

FROM centos
ENV name Docker
ENTRYPOINT ["/bin/echo","hello $name"]

然后制作镜像:

[vagrant@localhost test-command]$ docker build -t shenjianping0307/centos-entrypoint .
Sending build context to Docker daemon  2.048kB
Step 1/3 : FROM centos
 ---> 470671670cac
Step 2/3 : ENV name Docker
 ---> Using cache
 ---> e5aca6e78cba
Step 3/3 : ENTRYPOINT ["/bin/echo","hello $name"]
 ---> Running in 406fca203d44
Removing intermediate container 406fca203d44
 ---> 12eab087ba3c
Successfully built 12eab087ba3c
Successfully tagged shenjianping0307/centos-entrypoint:latest
View Code

可以看到这个执行的结果是失败的:

[vagrant@localhost test-command]$ docker run shenjianping0307/centos-entrypoint
hello $name

它没有将$name这个变量给替换出来,因为Exec执行的命令单纯的就是echo命令,没有在shell的环境下。

那么可以怎样修改就使得结果可行呢?修改Dockerfile文件:

FROM centos
ENV name Docker
ENTRYPOINT ["/bin/bash","-c","echo hello $name"]  #-c指定后面的都是命令参数

然后生成镜像,再执行就ok了。

总结:

#CMD
a、容器启动时的默认执行命令
b、如果docker run 后有其他命令,CMD命令将被忽略
c、如果有多个CMD命令,只会执行最后一个CMD

#ENTRYPOINT
a、让容器以应用程序或者服务形式运行(比如启动数据库服务等)
b、不会被忽略,一定会执行
#覆盖掉CMD命令
[vagrant@localhost test-command]$ docker run -it  shenjianping0307/centos-cmd /bin/bash   
[root@72379708f335 /]# 

#ENTRYPOINT一定会执行
[vagrant@localhost test-command]$ docker run -it shenjianping0307/centos-entrypoint-new /bin/bash
hello Docker
View Code

(三)容器命令

1、后台运行(-d参数)

[root@localhost vagrant]# docker run -d hello-world
9ab69b8a51ea4a103f9fdf5230dfb09314958d3dd1797739eeb4a61cfea1adf3

通过-d参数指定容器后台运行,返回容器的ID

2、exec

这个命令可以对已经正在运行的容器进行操作,包括进入到容器内部进行查看日志等信息(这个命令就是对运行中的容器执行某个命令)

[root@localhost vagrant]# docker exec -it 9ab69b8a51ea4a103f9fdf5230dfb09314958d3dd1797739eeb4a61cfea1adf3 /bin/bash

3、停止容器运行(stop)

[vagrant@localhost ~]$ docker stop 9ab6

4、查看正在运行的容器

[vagrant@localhost ~]$ docker ps

5、查看已经退出的容器

[vagrant@localhost ~]$ docker ps -a

6、获取容器的ID

[vagrant@localhost ~]$ docker ps -aq
88b0da62d57d

7、删掉所有退出状态的容器

[vagrant@localhost ~]$ docker rm $(docker ps -aq)

8、容器命名(--name)

如果不规定容器名称就会随机分配一个名称,但是可以通过--name参数指定名称

[vagrant@localhost ~]$ docker run -d --name=hello hello-world  #容器的名称就是hello,后续可以通过docker start hello;docker stop hello来操作容器

9、容器信息(inspect)

容器的一些信息,包括ID,created,网络等信息。

[vagrant@localhost ~]$ docker inspect 88b0da62d57d
[
    {
        "Id": "88b0da62d57dd4bdace11fa32713be90209a4e5024d855875a2a197238fae917",
        "Created": "2020-01-29T13:08:32.740086073Z",
        "Path": "/hello",
        "Args": [],
        "State": {
            "Status": "exited",
            "Running": false,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 0,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2020-01-29T13:08:34.240609354Z",
            "FinishedAt": "2020-01-29T13:08:34.162986756Z"
        },
        "Image": "sha256:fce289e99eb9bca977dae136fbe2a82b6b7d4c372474c9235adc1741675f587e",
        "ResolvConfPath": "/var/lib/docker/containers/88b0da62d57dd4bdace11fa32713be90209a4e5024d855875a2a197238fae917/resolv.conf",
        "HostnamePath": "/var/lib/docker/containers/88b0da62d57dd4bdace11fa32713be90209a4e5024d855875a2a197238fae917/hostname",
        "HostsPath": "/var/lib/docker/containers/88b0da62d57dd4bdace11fa32713be90209a4e5024d855875a2a197238fae917/hosts",
        "LogPath": "/var/lib/docker/containers/88b0da62d57dd4bdace11fa32713be90209a4e5024d855875a2a197238fae917/88b0da62d57dd4bdace11fa32713be90209a4e5024d855875a2a197238fae917-json.log",
        "Name": "/blissful_easley",
        "RestartCount": 0,
        "Driver": "overlay2",
        "Platform": "linux",
        "MountLabel": "",
        "ProcessLabel": "",
        "AppArmorProfile": "",
        "ExecIDs": null,
        "HostConfig": {
            "Binds": null,
            "ContainerIDFile": "",
            "LogConfig": {
                "Type": "json-file",
                "Config": {}
            },
            "NetworkMode": "default",
            "PortBindings": {},
            "RestartPolicy": {
                "Name": "no",
                "MaximumRetryCount": 0
            },
            "AutoRemove": false,
            "VolumeDriver": "",
            "VolumesFrom": null,
            "CapAdd": null,
            "CapDrop": null,
            "Capabilities": null,
            "Dns": [],
            "DnsOptions": [],
            "DnsSearch": [],
            "ExtraHosts": null,
            "GroupAdd": null,
            "IpcMode": "private",
            "Cgroup": "",
            "Links": null,
            "OomScoreAdj": 0,
            "PidMode": "",
            "Privileged": false,
            "PublishAllPorts": false,
            "ReadonlyRootfs": false,
            "SecurityOpt": null,
            "UTSMode": "",
            "UsernsMode": "",
            "ShmSize": 67108864,
            "Runtime": "runc",
            "ConsoleSize": [
                0,
                0
            ],
            "Isolation": "",
            "CpuShares": 0,
            "Memory": 0,
            "NanoCpus": 0,
            "CgroupParent": "",
            "BlkioWeight": 0,
            "BlkioWeightDevice": [],
            "BlkioDeviceReadBps": null,
            "BlkioDeviceWriteBps": null,
            "BlkioDeviceReadIOps": null,
            "BlkioDeviceWriteIOps": null,
            "CpuPeriod": 0,
            "CpuQuota": 0,
            "CpuRealtimePeriod": 0,
            "CpuRealtimeRuntime": 0,
            "CpusetCpus": "",
            "CpusetMems": "",
            "Devices": [],
            "DeviceCgroupRules": null,
            "DeviceRequests": null,
            "KernelMemory": 0,
            "KernelMemoryTCP": 0,
            "MemoryReservation": 0,
            "MemorySwap": 0,
            "MemorySwappiness": null,
            "OomKillDisable": false,
            "PidsLimit": null,
            "Ulimits": null,
            "CpuCount": 0,
            "CpuPercent": 0,
            "IOMaximumIOps": 0,
            "IOMaximumBandwidth": 0,
            "MaskedPaths": [
                "/proc/asound",
                "/proc/acpi",
                "/proc/kcore",
                "/proc/keys",
                "/proc/latency_stats",
                "/proc/timer_list",
                "/proc/timer_stats",
                "/proc/sched_debug",
                "/proc/scsi",
                "/sys/firmware"
            ],
            "ReadonlyPaths": [
                "/proc/bus",
                "/proc/fs",
                "/proc/irq",
                "/proc/sys",
                "/proc/sysrq-trigger"
            ]
        },
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/c2e06ee78c34f087122e5d228f0992262a6ecc04c696722a5704a4b777b91dda-init/diff:/var/lib/docker/overlay2/d9962cd997ab1fe909b3ba671af6f3a1b422ba7d49145b04736c5727d847c52d/diff",
                "MergedDir": "/var/lib/docker/overlay2/c2e06ee78c34f087122e5d228f0992262a6ecc04c696722a5704a4b777b91dda/merged",
                "UpperDir": "/var/lib/docker/overlay2/c2e06ee78c34f087122e5d228f0992262a6ecc04c696722a5704a4b777b91dda/diff",
                "WorkDir": "/var/lib/docker/overlay2/c2e06ee78c34f087122e5d228f0992262a6ecc04c696722a5704a4b777b91dda/work"
            },
            "Name": "overlay2"
        },
        "Mounts": [],
        "Config": {
            "Hostname": "88b0da62d57d",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": true,
            "AttachStderr": true,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
            "Cmd": [
                "/hello"
            ],
            "Image": "hello-world",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": {}
        },
        "NetworkSettings": {
            "Bridge": "",
            "SandboxID": "d38a7ac6dd5469d8964a81f16021bbc06ac87266eafc2c20bec29845898ff0e0",
            "HairpinMode": false,
            "LinkLocalIPv6Address": "",
            "LinkLocalIPv6PrefixLen": 0,
            "Ports": {},
            "SandboxKey": "/var/run/docker/netns/d38a7ac6dd54",
            "SecondaryIPAddresses": null,
            "SecondaryIPv6Addresses": null,
            "EndpointID": "",
            "Gateway": "",
            "GlobalIPv6Address": "",
            "GlobalIPv6PrefixLen": 0,
            "IPAddress": "",
            "IPPrefixLen": 0,
            "IPv6Gateway": "",
            "MacAddress": "",
            "Networks": {
                "bridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "NetworkID": "738605add8227bd6f264a8c21a14dff43d797f1d0bba0a3ff5ce069d319fc127",
                    "EndpointID": "",
                    "Gateway": "",
                    "IPAddress": "",
                    "IPPrefixLen": 0,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "",
                    "DriverOpts": null
                }
            }
        }
    }
]
详细信息

三、实战

(一)运行Web程序

1、新建Web文件夹

[vagrant@localhost ~]$ mkdir Web

2、建立app.py文件以及Dockerfile文件

[vagrant@localhost ~]$ cd Web/
[vagrant@localhost Web]$ touch app.py
[vagrant@localhost Web]$ touch Dockerfile
[vagrant@localhost Web]$ ls
app.py  Dockerfile

3、app.py中写入web程序

from flask import Flask
app = Flask(__name__)
@app.route('/')
def test():
   return "test"
if __name__ == "__main__":
   app.run(host="0.0.0.0",port=5000)

4、编写Dockerfile文件

FROM python:2.7   #基础镜像
LABEL maintainer="shenjianping0307@gmail.com"  #作者信息
RUN pip install flask  #运行环境所需要的包
COPY app.py /app/    #将本地文件拷贝到镜像app目录下中 /app/app.py
WORKDIR /app    #进入到工作目录,相当于cd  /app/ ,否则CMD命令找不到可执行文件app.py
EXPOSE 5000    #暴露端口
CMD ["python","app.py"]  #运行文件,相当于python app.py

5、生成镜像

[vagrant@localhost Web]$ docker build -t shenjianping0307/app .

(二)stress工具 

1、容器中安装stress

  • 下载ubuntu镜像
[root@localhost Web]# docker pull ubuntu
  • 运行ubuntu镜像
[root@localhost Web]# docker run -it ubuntu
root@fd1ab8e81c64:/# 
  • 容器中安装stress工具
root@fd1ab8e81c64:/# apt-get update && apt-get install -y stress

安装完毕后可以看到安装成功:

root@fd1ab8e81c64:/# which stress
/usr/bin/stress

另外,可以看看stress的命令:

root@fd1ab8e81c64:/# stress --help
Usage: stress [OPTION [ARG]] ...
 -?, --help         show this help statement
     --version      show version statement
 -v, --verbose      be verbose
 -q, --quiet        be quiet
 -n, --dry-run      show what would have been done
 -t, --timeout N    timeout after N seconds
     --backoff N    wait factor of N microseconds before work starts
 -c, --cpu N        spawn N workers spinning on sqrt()
 -i, --io N         spawn N workers spinning on sync()
 -m, --vm N         spawn N workers spinning on malloc()/free()
     --vm-bytes B   malloc B bytes per vm worker (default is 256MB)
     --vm-stride B  touch a byte every B bytes (default is 4096)
     --vm-hang N    sleep N secs before free (default none, 0 is inf)
     --vm-keep      redirty memory instead of freeing and reallocating
 -d, --hdd N        spawn N workers spinning on write()/unlink()
     --hdd-bytes B  write B bytes per hdd worker (default is 1GB)
View Code
  • 进行测试
root@fd1ab8e81c64:/#  stress --vm 1 --verbose

#注意:
#--vm表示起的进程有几个  默认的大小是256M
#--verbose 详细的日志

2、Dockerfile制作stress工具

  • 创建Dockerfile文件
[root@localhost vagrant]# mkdir ubuntu-stress
[root@localhost vagrant]# cd ubuntu-stress/
[root@localhost ubuntu-stress]# touch Dockerfile  #创建Dockerfile文件
  • 写入内容
FROM ubuntu
RUN apt-get update && apt-get -y install stress
ENTRYPOINT ["/usr/bin/stress"]
CMD []     #参数,例如--vm之类的
  • 生成镜像
[root@localhost ubuntu-stress]# docker build -t shenjianping0307/ubuntu-stress .
  • 运行镜像
[root@localhost ubuntu-stress]# docker run -it shenjianping0307/ubuntu-stress --vm 1 
stress: info: [1] dispatching hogs: 0 cpu, 0 io, 1 vm, 0 hdd

 

posted @ 2020-02-06 20:34  iveBoy  阅读(437)  评论(0编辑  收藏  举报
TOP