Docker(一)

容器与虚拟机

  • 容器能与主机的操作系统共享资源,因而它的效率高出一个数量级。启动和停止容器,只需在一瞬间。相比直接在主机上运行程序,容器的性能损耗非常低,甚至是零损耗。
  • 容器具有可移植性
  • 容器是轻量的,意味着开发者能同时运行数十个容器,新功能模拟分布式系统在真实运行环境下的情况。
  • 对于最终用户及开发者而言,用户可以下载并执行复杂的应用程序,而无需花费大量时间在配置和安装的问题上,也无需要担心对系统本身的改动。
jason@Jason ~ % docker run debian echo "Hello World"
Unable to find image 'debian:latest' locally
latest: Pulling from library/debian
756975cb9c7e: Downloading
latest: Pulling from library/debian
756975cb9c7e: Pull complete
Digest: sha256:e2cc6fb403be437ef8af68bdc3a89fd58e80b4e390c58f14c77c466002391193
Status: Downloaded newer image for debian:latest
Hello World
jason@Jason ~ %

清理已经停止的容器

docker rm -v $(docker ps -qa -f status=exited)

docker run 时加上 --rm 参数,它的作用是当容器退出时,容器和相关的文件系统会被一并删除

jason@Jason ~ % docker run -it --name cowsay --hostname cowsay debian bash
root@cowsay:/#
root@cowsay:/# apt-get update
Get:1 http://security.debian.org/debian-security buster/updates InRelease [65.4 kB]
Get:2 http://security.debian.org/debian-security buster/updates/main amd64 Packages [254 kB]
Get:3 http://deb.debian.org/debian buster InRelease [121 kB]
Get:4 http://deb.debian.org/debian buster-updates InRelease [51.9 kB]
Get:5 http://deb.debian.org/debian buster/main amd64 Packages [7906 kB]
Get:6 http://deb.debian.org/debian buster-updates/main amd64 Packages [7856 B]
Fetched 8407 kB in 4s (2279 kB/s)
Reading package lists... Done
root@cowsay:/#
root@cowsay:/# apt-get install -y cowsay fortune

docker commit把容器转成镜像,无论容器是在运行中还是在停止状态都可以

jason@Jason ~ % docker commit cowsay test/cowsayimage
sha256:15f184e7042102b68e25b774fe3bb65464d57c543df78d890079e180834e71f7
jason@Jason ~ %
jason@Jason ~ % docker images
REPOSITORY          TAG                 IMAGE ID            CREATED              SIZE
test/cowsayimage    latest              15f184e70421        About a minute ago   181MB
jason@Jason ~ %
jason@Jason ~ %

根据生成的镜像创建容器

jason@Jason ~ % docker run --rm test/cowsayimage /usr/games/cowsay "Moo"
 _____
< Moo >
 -----
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
jason@Jason ~ %

Dockerfile

jason@Jason ~ % mkdir cowsay
jason@Jason ~ % cd cowsay
jason@Jason cowsay % touch Dockerfile
jason@Jason cowsay %

Dockerfile 中写入以下内容:

FROM debian

RUN apt-get update && apt-get install -y cowsay fortune

FROM 指令指定初始镜像,Dockerfile一定要有FROM指令作为第一个非注释指令。
RUN 指令指定的 shell 命令,是将要在镜像里执行的。

jason@Jason cowsay % docker build -t test/cowsay-dockerfile .
Sending build context to Docker daemon  2.048kB
Step 1/2 : FROM debian
 ---> ef05c61d5112
Step 2/2 : RUN apt-get update && apt-get install -y cowsay fortune
 ---> Running in 9c06a2bf1acc
 ...
Setting up cowsay (3.03+dfsg2-6) ...
Processing triggers for libc-bin (2.28-10) ...
Removing intermediate container 9c06a2bf1acc
 ---> 559b7924217e
Successfully built 559b7924217e
Successfully tagged test/cowsay-dockerfile:latest
jason@Jason cowsay %
jason@Jason cowsay % docker images
REPOSITORY               TAG                 IMAGE ID            CREATED             SIZE
test/cowsay-dockerfile   latest              559b7924217e        2 minutes ago       181MB
test/cowsayimage         latest              15f184e70421        11 minutes ago      181MB
debian                   latest              ef05c61d5112        2 weeks ago         114MB
jason@Jason cowsay %
jason@Jason cowsay % docker run --rm test/cowsay-dockerfile /usr/games/cowsay "Moo"
 _____
< Moo >
 -----
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
jason@Jason cowsay %

联合文件系统,允许多个文件系统叠加,并表现为一个单一的文件系统。
文件夹中的文件可以来自多个文件系统,但如果有两个文件的路径完全相,最后挂载的文件则会覆盖较早前挂载的文件。

Docker 的镜像由多个不同的层(layer)组成,每一个层都是一个只读的文件系统。
Dockerfile 里的每个指令都会创建一个新的层,而这个层位于前一个层之上。

当一个镜像被转化成一个容器时(docker run 或 docker create),Docker引擎会在镜像之上添加一个处于最上层的可读写文件系统(同时还会对一些配置进行初始化,如IP地址,名称,ID等)。

由于不必要的层会使镜像变得臃肿,所以Dockerfile会把多个UNIX命令放在同一个 RUN 指令中,以减少层的数量。

容器可以处于几种状态:createdrestartingrunningpausedexited

restarting 状态比较少见,当 Docker 引擎尝试重启一个启动失败的容器时,它才会出现。

DockerfileENTRYPOINT 指令,可以让用户更易于使用这个镜像:

FROM debian

RUN apt-get update && apt-get install -y cowsay fortune

ENTRYPOINT ["/usr/games/cowsay"]
jason@Jason cowsay % docker build -t test/cowsay-dockerfile .
Sending build context to Docker daemon  2.048kB
Step 1/3 : FROM debian
 ---> ef05c61d5112
Step 2/3 : RUN apt-get update && apt-get install -y cowsay fortune
 ---> Using cache
 ---> 559b7924217e
Step 3/3 : ENTRYPOINT ["/usr/games/cowsay"]
 ---> Running in 4f8163ac1aa0
Removing intermediate container 4f8163ac1aa0
 ---> 6015f6f41264
Successfully built 6015f6f41264
Successfully tagged test/cowsay-dockerfile:latest
jason@Jason cowsay %
jason@Jason cowsay % docker run --rm test/cowsay-dockerfile "Moo"
 _____
< Moo >
 -----
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
jason@Jason cowsay %

可以将 ENTRYPOINT 指定为一个脚本

jason@Jason cowsay % touch entrypoint.sh
jason@Jason cowsay % chmod +x entrypoint.sh
jason@Jason cowsay %

entrypoint.sh

#!/bin/bash

if [ $# -eq 0 ]; then
        /usr/games/fortune | /usr/games/cowsay
else
        /usr/games/cowsay "$@"
fi

Dockerfile

FROM debian

RUN apt-get update && apt-get install -y cowsay fortune
COPY entrypoint.sh /

ENTRYPOINT ["/entrypoint.sh"]
jason@Jason cowsay % docker build -t test/cowsay-dockerfile .
Sending build context to Docker daemon  3.072kB
Step 1/4 : FROM debian
 ---> ef05c61d5112
Step 2/4 : RUN apt-get update && apt-get install -y cowsay fortune
 ---> Using cache
 ---> 559b7924217e
Step 3/4 : COPY entrypoint.sh /
 ---> dab9fcb602fb
Step 4/4 : ENTRYPOINT ["/entrypoint.sh"]
 ---> Running in 725a2cec481f
Removing intermediate container 725a2cec481f
 ---> a699a0024aee
Successfully built a699a0024aee
Successfully tagged test/cowsay-dockerfile:latest
jason@Jason cowsay %
jason@Jason cowsay %
jason@Jason cowsay % docker run --rm test/cowsay-dockerfile
 _________________________________________
/ Don't read any sky-writing for the next \
\ two weeks.                              /
 -----------------------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
jason@Jason cowsay %
jason@Jason cowsay %
jason@Jason cowsay % docker run --rm test/cowsay-dockerfile Hello Moo
 ___________
< Hello Moo >
 -----------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
jason@Jason cowsay %

在次cowsay镜像上传到 DockerHub上时,在 Dockerfile 内加入 MAINTAINER 指令,给镜像设定作者的联系信息:

FROM debian

MAINTAINER Jason Zhang <jason@zhang.com>
RUN apt-get update && apt-get install -y cowsay fortune
COPY entrypoint.sh /

ENTRYPOINT ["/entrypoint.sh"]

提交到 DockerHub

docker build -t jason/cowsay .
docker push jason/cowsay

指定标签:

docker build -t jason/cowsay:stable .

镜像的命名空间:

  • 镜像名称以字符串和/开头,如:jason/cowsay,那么它属于用户命名空间
  • 如 debian 或ubuntu 的名称,不包含前缀或/,属于根命名空间。
  • 以主机名或IP开头的名称,代表该镜像来自第三方的寄存服务。

使用官方的镜像

jason@Jason ~ % docker pull redis
Using default tag: latest
latest: Pulling from library/redis
852e50cd189d: Pull complete
76190fa64fb8: Pull complete
9cbb1b61e01b: Pull complete
d048021f2aae: Pull complete
6f4b2af24926: Pull complete
1cf1d6922fba: Pull complete
Digest: sha256:5b98e32b58cdbf9f6b6f77072c4915d5ebec43912114031f37fa5fa25b032489
Status: Downloaded newer image for redis:latest
docker.io/library/redis:latest
jason@Jason ~ %

-d 参数记容器在后台运行

jason@Jason ~ % docker run --name myredis -d redis
44e9cc7b284fb1ced50f6b980acde1a586dee2b2437abdd7195319b1a9d40039
jason@Jason ~ %

再启动一个新的容器来作为 redis-cli 客户端角色,并把两个容器连接上:

jason@Jason ~ % docker run --rm -it --link myredis:redis redis /bin/bash
root@c25960b09515:/data#
root@c25960b09515:/data# redis-cli -h redis -p 6379
redis:6379> ping
PONG
redis:6379> set 'abc' 123
OK
redis:6379> get abc
"123"
redis:6379>

--link 命令可以把容器连接起来。

--link myredis:redis 把新的容器与已存在的myredis容器连接起来,并且在阐析容器中以redis作为myredis容器的主机名。

Docker 通过 数据卷(volume),实现容器与主机,或者容器与其他容器之间轻松共享数据

声明数据卷的两种方法:
第一种:在Dockerfile中使用 VOLUME 指令
第二种:在执行 docker run 的时候使用 -v 参数
VOLUME /data

docker run -v /data test/webserver

默认情况下,目录或文件会挂载在主机的Docker安装目录下
执行docker run的时候,可以指定用于挂载的主机目录,如:docker run -v /host/dir:/container/dir test/webserver

出于可移植性和安全方面的考虑,主机目录是无法在 Dockerfile 中指定的。

如何为Redis容器做备份呢?假设myredis容器还在运行中

jason@Jason ~ % docker run --rm -it --link myredis:redis redis /bin/bash
root@e7c04ee79a47:/data# redis-cli -h redis -p 6379
redis:6379> set abc 123
OK
redis:6379> get abc
"123"
redis:6379> save
OK
redis:6379>
redis:6379> exit
root@e7c04ee79a47:/data# exit
exit
jason@Jason ~ %
jason@Jason ~ % docker run --rm --volumes-from myredis -v $(pwd)/backup:/backup debian cp /data/dump.rdb /backup/
jason@Jason ~ %
jason@Jason ~ % ll backup | grep dump
-rw-r--r--  1 jason  staff         104 12  4 18:59 dump.rdb
jason@Jason ~ %

这里-v参数挂载一个主机上已知的目录,并通过--volumes-from将新容器连接至redis数据库目录

停止并删除myredis容器:

jason@Jason ~ % docker stop myredis
myredis
jason@Jason ~ %
jason@Jason ~ % docker rm -v myredis
myredis
jason@Jason ~ %

发表评论

您的电子邮箱地址不会被公开。