软件开发最大的麻烦事之一,就是环境配置。用户计算机的环境不相同,可能导致软件无法运行。
要使软件运行正确,用户必须保证两件事:操作系统的设置,各种库和组件的安装。只有它们都正确,软件才能运行。
那么怎么才能解决这个大问题呢?
虚拟机是个好方案~
但是容器化对于资源的消耗会小很多,会是个更优的选择。docker就是Linux容器中最受欢迎的一个。
在上周六与本周三的复习课程中,芒果就带大家一起认识了Docker,这里我们对Docker的基本使用做个小总结。
Docker介绍
Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux或Windows 机器上,也可以实现虚拟化。
要理解Docker的工作原理,需要对以下三个概念有足够清晰的认识。
镜像
我们都知道,操作系统分为内核和用户空间。对于 Linux 而言,内核启动后,会挂载 root 文件系统为其提供用户空间支持。而 Docker 镜像(Image),就相当于是一个 root 文件系统。比如官方镜像 ubuntu:18.04 就包含了完整的一套 Ubuntu 18.04 最小系统的 root 文件系统。
Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。
容器
镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的 类 和 实例 一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。
容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的命名空间。因此容器可以拥有自己的 root 文件系统、自己的网络配置、自己的进程空间,甚至自己的用户 ID 空间。容器内的进程是运行在一个隔离的环境里,使用起来,就好像是在一个独立于宿主的系统下操作一样。
每一个容器运行时,是以镜像为基础层,在其上创建一个当前容器的存储层,我们可以称这个为容器运行时读写而准备的存储层为容器存储层。容器存储层的生存周期和容器一样,容器消亡时,容器存储层也随之消亡。
仓库
镜像构建完成后,可以很容易的在当前宿主机上运行,但是,如果需要在其它服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务,Docker Registry 就是这样的服务。
三者之间关系
如下图所示:
其中Docker Client端向Docker守护进程发送请求,新建或者操作容器等。
Docker安装
Docker 是一个开源的商业产品,有两个版本:社区版(Community Edition,缩写为 CE)和企业版(Enterprise Edition,缩写为 EE)。企业版包含了一些收费服务,个人开发者一般用不到,所以我们仅仅安装使用社区版。
这里安装系统为CentOS 7:
代码语言:javascript复制#安装一些必要的系统工具
yum install -y yum-utils device-mapper-persistent-data lvm2
#添加软件源信息
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
#更新 yum 缓存
yum makecache
#安装 Docker-ce
yum -y install docker-ce
还可以通过安装脚本一键安装:
代码语言:javascript复制#安装curl
yum -y install curl
#执行 Docker 安装脚本(自动安装docker所需的依赖,并安装启动docker)
curl https://get.docker.com/ | sudo sh
#启动 Docker 服务
systemctl start docker
更多系统版本安装请参考:
https://docs.docker.com/install/
Docker使用
获取镜像
Docker Hub 上有大量的高质量的镜像可以用。从 Docker 镜像仓库获取镜像的命令是 docker pull。其命令格式为:
docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签]
Docker 镜像仓库地址:地址的格式一般是 <域名/IP>[:端口号]。默认地址是 Docker Hub。
仓库名:如之前所说,这里的仓库名是两段式名称,即 <用户名>/<软件名>。对于 Docker Hub,如果不给出用户名,则默认为 library,也就是官方镜像。
例:
docker pull ubuntu:18.04
列出镜像
要想列出已经下载下来的镜像,可以使用 docker image ls 命令。
结果列表包含了仓库名、标签、镜像 ID、创建时间 以及 所占用的空间。镜像 ID 则是镜像的唯一标识,一个镜像可以对应多个标签。
例:
docker image ls –q
删除镜像
如果要删除本地的镜像,可以使用 docker image rm 命令,其格式为:
docker image rm [选项] <镜像1> [<镜像2> ...]
其中,<镜像> 可以是 镜像短 ID、镜像长 ID、镜像名 或者 镜像摘要。
例:
docker image rm centos
docker image rm $(docker image ls -q centos)
新建并启动容器
所需要的命令主要为 docker run。
例如,下面的命令输出一个 “Hello World”,之后终止容器。
docker run ubuntu:18.04 /bin/echo 'Hello world’
这跟在本地直接执行 /bin/echo 'hello world' 几乎感觉不出任何区别。
下面的命令则启动一个 bash 终端,允许用户进行交互。
$ docker run -t -i ubuntu:18.04 /bin/bash
root@af8bae53bdd3:/#
其中,-t 选项让Docker分配一个伪终端(pseudo-tty)并绑定到容器的标准输入上, -i 则让容器的标准输入保持打开。
在交互模式下,用户可以通过所创建的终端来输入命令。
启动已终止容器
如果使用了 -d 参数运行容器。
$ docker run --name ubuntu_test -d ubuntu:18.04 /bin/sh -c "while true; do echo hello world; sleep 1; done"
此时容器会在后台运行并不会把输出的结果 (STDOUT) 打印到宿主机上面(输出结果可以用 docker logs 查看)。
注:容器是否会长久运行,是和 docker run 指定的命令有关,和 -d 参数无关。
使用 -d 参数启动后会返回一个唯一的 id。
可以通过 docker container ls 或者 docker ps -a命令来查看容器信息。
要获取容器的输出信息,可以通过 docker container logs 命令。
docker container logs [container ID or NAMES]
可以利用 docker container start 命令,直接将一个已经终止的容器启动运行。
例:
docker container start ubuntu_test
容器的核心为所执行的应用程序,所需要的资源都是应用程序运行所必需的。除此之外,并没有其它的资源。可以在伪终端中利用 ps 或 top 来查看进程信息。
终止容器
可以使用 docker container stop 来终止一个运行中的容器。
此外,当 Docker 容器中指定的应用终结时,容器也自动终止。
用户通过 exit 命令或 Ctrl d 来退出终端时,所创建的容器立刻终止。
例:
docker container stop ubuntu_test
终止状态的容器可以用 docker container ls -a 命令看到。
例:
docker container ls –a
处于终止状态的容器,可以通过 docker container start 命令来重新启动。
此外,docker container restart 命令会将一个运行态的容器终止,然后再重新启动它。
进入容器
在使用 -d 参数时,容器启动后会进入后台。
某些时候需要进入容器进行操作,包括使用 docker attach 命令或 docker exec 命令。
attach 命令
例:
docker attach ubuntu_test
注意:如果从这个 stdin 中 exit,会导致容器的停止。
exec 命令
docker exec 后边可以跟多个参数,常用参数为-i -t 参数。
只用 -i 参数时,由于没有分配伪终端,界面没有我们熟悉的 Linux 命令提示符,但命令执行结果仍然可以返回。
当 -i -t 参数一起使用时,则可以看到我们熟悉的 Linux 命令提示符。
例:
docker exec -it ubuntu_test bash
如果从这个 stdin 中 exit,不会导致容器的停止。这就是为什么推荐大家使用 docker exec 的原因。
删除容器
如果要删除本地某个容器,可以使用 docker rm 命令。
docker rm ubuntu_test
这样将导出容器快照到本地文件。
关于Docker镜像以及容器的使用内容非常多,因为篇幅原因,我们仅仅介绍以上部分,对于更多的内容,我们会在之后的文章进行更新。