Docker基础知识
Docker是什么
Docker 最初是 dotCloud 公司创始人 Solomon Hykes 在法国期间发起的一个公司内部项目,它是基于 dotCloud 公司多年云服务技术的一次革新,并于 2013 年 3 月以 Apache 2.0 授权协议开源,主要项目代码在 GitHub 上进行维护。
Docker 使用 Google 公司推出的 Go 语言 进行开发实现,基于 Linux 内核的 cgroup,namespace,以及AUFS 类的 Union FS 等技术,对进程进行封装隔离,属于 操作系统层面的虚拟化技术。由于隔离的进程独立于宿主和其它的隔离的进程,因此也称其为容器。
Docker 在容器的基础上,进行了进一步的封装,从文件系统、网络互联到进程隔离等等,极大的简化了容器的创建和维护。使得 Docker 技术比虚拟机技术更为轻便、快捷。
为什么要用Docker
环境配置一直是软件开发的麻烦之一。用户计算机的环境都不相同,同样的软件,换了一台机器可能根本无法运行。环境包括操作系统的设置,各种库和组件的安装。只有它们都正确,软件才能运行。举例来说,安装一个 Python 应用,计算机必须有 Python 引擎,还必须有各种依赖,可能还要配置环境变量。
环境配置如此麻烦,换一台机器,就要重来一次,让人身心俱疲。那么,软件可不可以附带环境安装?也就是说,安装的时候,能否把可运行的原始环境复制过来? Docker就是来解决这个问题的。
Docker 与 虚拟机
这么听起来,Docker与虚拟机好像是一个东西。确实,它们都是带环境安装的不同解决方案,然而,虚拟机有以下几个劣势:
资源占用多
虚拟机会独占一部分内存和硬盘空间。它运行的时候,其他程序就不能使用这些资源了。哪怕虚拟机里面的应用程序,真正使用的内存只有 1MB,虚拟机依然需要几百 MB 的内存才能运行。
冗余步骤多
虚拟机是完整的操作系统,一些系统级别的操作步骤,往往无法跳过,比如用户登录。
启动慢
启动操作系统需要多久,启动虚拟机就需要多久。可能要等几分钟,应用程序才能真正运行。
由于虚拟机存在这些缺点,Linux 发展出了另一种虚拟化技术:Linux 容器(Linux Containers,缩写为 LXC)。Linux 容器不是模拟一个完整的操作系统,而是对进程进行隔离。显然,直接对进程隔离,容器的几大优势就体现出来了:
- 启动快
- 资源占用少
- 体积小
Docker 属于 Linux 容器的一种封装,提供简单易用的容器使用接口。它是目前最流行的 Linux 容器解决方案。
虚拟机与Docker对比:
安装Docker
以下以 ubuntu Xenial 16.04 (LTS) 为例,安装Docker社区版(Docker CE),
其它操作系统下的安装可能略有不同,详见Get Docker CE for Ubuntu
首先,如果需要卸载旧版Docker:
1 | sudo apt-get remove docker docker-engine docker.io containerd runc |
在一台新主机上安装Docker时,官方推荐使用Docker仓库来安装,此后可以很方便地从仓库安装和更新Docker。由于 apt
源使用 HTTPS 以确保软件下载过程中不被篡改。因此,我们首先需要添加使用 HTTPS 传输的软件包以及 CA 证书。
1 | sudo apt-get update |
添加Docker官方的GPG秘钥:
1 | curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - |
如果下载失败,可以挂代理,或者直接在我的仓库获取
验证秘钥
1 | sudo apt-key fingerprint 0EBFCD88 |
能看到包含9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88
的输出就证明正确的安装了Docker CE的秘钥。
添加repo,并更新 apt
1 | sudo add-apt-repository \ |
安装Docker时,可以直接选择安装最新版本:
1 | sudo apt-get install docker-ce |
也可以指定版本:
1 | sudo apt-get install docker-ce=<VERSION> |
如果需要查看可用版本:
1 | apt-cache madison docker-ce |
就是列出版本,版本号等信息。例如,我的输出如下:
1 | docker-ce | 18.03.0~ce-0~ubuntu | https://download.docker.com/linux/ubuntu artful/stable amd64 Packages |
Docker Hello world
1 | sudo docker run hello-world |
docker会首先从本地查找hello-world
镜像:
1 | Unable to find image 'hello-world:latest' locally |
当本地不存在这个镜像时,会尝试从远程仓库拉取镜像。
当然,由于某些众所周知的原因,你可能会在拉取镜像的时候会遭遇以下错误:
1 | 9bb5a5d4561a: Pulling fs layer |
解决方法也很简单:
- 科学地上网
- 修改默认远程镜像仓库
Docker为中国也提供了官方的镜像库:https://registry.docker-cn.com ,但是个人感觉也并不快。国内还有很多镜像库可以使用,例如阿里云,网易云,DaoCloud等。以下以配置阿里云镜像库为例。
要获得阿里云的镜像加速服务,需要注册成为阿里云用户。登录后,在阿里云的管理控制台 -> 容器镜像服务 -> 镜像加速器
可以看到配置文件以及其中的链接。链接为https://[yourcode].mirror.aliyun.com
,其中[yourcode]
为每个注册用户的专属代码。
配置方法如下:
Ubuntu 16.04+、Debian 8+、CentOS 7(其它旧版本可能有差异 )
1
sudo vim /etc/docker/daemon.json
写入以下内容:
1
2
3{
"registry-mirrors": ["https://[yourcode].mirror.aliyun.com"]
}重启服务:
1
2sudo systemctl daemon-reload
sudo systemctl restart docker
之后,可以通过sudo docker info
查看 Registry Mirrors 信息,就能看到配置好的镜像仓库了。
重新运行hello-world
1 | sudo docker run hello-world |
1 | Unable to find image 'hello-world:latest' locally |
此时,已经能够成功从国内镜像库拉取镜像了。
镜像,容器 与 仓库
Docker中最重要的三个基本概念就是镜像(image),容器(container) 与 仓库(Repository)。详细介绍参见Docker基本概念
以刚才运行的hello-world
为例。hello-world:latest
是一个镜像,查看镜像:
1 | sudo docker image ls |
命令docker run hello-world
实际上是一个创建容器并启动的过程。
镜像(
Image
)和容器(Container
)的关系,就像是面向对象程序设计中的类
和实例
一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。
查看容器的命令如下:
1 | sudo docker container ls |
但是,我们什么都没看到。这是因为,已经终止的容器,不会被列出。而hello-world
的作用是输出一个 “Hello World”,之后终止容器。因此,此时该容器已经终止。加上-a
参数可以查看已经终止的容器:
1 | sudo docker container ls -a |
可以用docker container rm [Container]
来删除一个处于终止状态的容器,也可以用docker container prune
清理掉所有处于终止状态的容器。
镜像的更多操作:使用 Docker 镜像。容器的更多操作:操作 Docker 容器
Docker nginx 实战入门
接下来,我们以个人博客为例,用docker+nginx部署自己的个人博客。其中,nginx
的作用在这里只是一个静态文件服务器。
获取镜像
想要获取一个镜像,最简单的方法,就是查看是否已经有了满足要求的镜像。命令行查看:
1 | sudo docker search nginx |
当然,你也可以直接上官方镜像站的网页查看。
事实是,常用镜像,一般来说都会有很多优质镜像已经被搭建好。像Nginx
这样的,还有官方(Official)镜像。可以直接拉取官方nginx
镜像:
1 | sudo docker pull nginx |
当然,你也可以自己用Dockerfile
构建一个自己的镜像,这个我们以后再说。
首先,假设你已经有了自己博客的所有静态文件(至少有一个index.html
)
并且写好了nginx
的配置文件blog.config
,那么就可以开始运行你的第一个容器了。
以上准备的文件,容器的运行都会需要,然而正如上文所说,容器是可以完全与当前宿主环境隔离的,那么,如何让容器访问/拥有它们呢?解决这个问题一般有两种方法:
- 将文件放入(拷贝到)容器中。
- 挂载到容器中。
这篇文章里,我们暂时只使用挂载这一种方法。
将blog.conf
放在/home/ace/Documnets/sites-enabled/
(这是我的个人目录)下,blog/
放在/home/ace/Documnets/
下,就可以开始挂载文件并启动容器了:
1 | sudo docker run --name myNginx \ |
这一串命令实际上是docker run [FLAGS] nginx
-d
是将容器放在后台运行,-p
指定端口映射,即将容器的8080端口映射到主机的8081端口,也就是说,我们在主机中访问8081端口的时候,就可以访问到容器内部的8080端口。这里使用8081是因为我本机的8080端口已经在使用了。
-v
表示挂载,可以简单的理解为:当容器中的nginx
运行时,如果要访问到/static
目录时,实际访问到的是宿主机(即你的电脑)的/home/ace/Documents/blog
目录。同理,sites-enabled
目录也形成了映射。一般来说,官方建议挂载目录而不是挂载文件。另外,熟悉nginx的话会知道,最官方/规范的做法是将这个配置文件放在/etc/nginx/sites-available/
下,再建立软链接。
容器开始运行后,在浏览器中访问localhost:8081
,就可以看到博客了:
Trouble-shooting
遇到错误中带有提示TLS
或者HTTP/HTTPS时
,配置了国内镜像库能解决80%的问题,科学的上网能解决90%的问题。
默认情况下,docker
命令会使用 Unix socket 与 Docker 引擎通讯。而只有 root
用户和 docker
组的用户才可以访问 Docker 引擎的 Unix socket。出于安全考虑,一般 Linux 系统上不会直接使用 root
用户。因此,为了避免每次输入命令都需要sudo
,可以选择使用 docker
的用户加入 docker
用户组:
1 | sudo usermod -aG docker $USER |
本文为博主原创文章,转载请注明出处。