如何在Ubuntu14.04上的Docker容器中运行Nginx
介绍
本教程展示了如何在 Docker 容器中部署 Nginx。
通过容器化 Nginx,我们减少了系统管理员的开销。 我们将不再需要通过包管理器管理 Nginx 或从源代码构建它。 Docker 容器允许我们在 Nginx 的新版本发布时简单地替换整个容器。 我们只需要维护 Nginx 配置文件和我们的内容。
Nginx 将自己描述为:
nginx [engine x] 是 HTTP 和反向代理服务器、邮件代理服务器和通用 TCP 代理服务器,最初由 Igor Sysoev 编写。
在实践中,许多系统管理员使用 Nginx 来提供 Web 内容,从平面文件网站到 NodeJS 中的上游 API。 在本教程中,我们将提供一个基本网页,因此我们可以专注于使用 Docker 容器配置 Nginx。
Docker 容器是一种比较古老的操作实践的流行形式:容器化。 容器化与虚拟化的不同之处在于,虚拟化抽象了硬件,而容器化也抽象了基础操作系统。 实际上,这意味着我们可以获取一个应用程序(或一组应用程序)并将它们包装在一个容器(或多个容器)中,以使它们模块化、可移植、可组合和轻量级。
这种可移植性意味着您可以在各种操作系统上安装 Docker Engine(也称为 Docker Core,甚至只是 Docker),任何人编写的任何功能性容器都可以在其上运行。
如果您想了解有关 Docker 的更多信息,可以查看 Docker 入门教程 。
出于本文的目的,我们将在 Ubuntu 14.04 上安装 Docker 引擎。
我们将为 Ubuntu 安装当前稳定版本的 Docker,即 1.8.1。
本教程面向 Docker 新手的 Nginx 用户。 如果你只需要简单的命令来设置你的 Nginx 容器,你可以执行第 1 步,然后跳到第 5 步。
如果您想逐步构建您的容器并了解端口映射和分离模式,请按照整个教程进行操作。
先决条件
要容器化 Nginx,请完成以下操作:
- 设置 Ubuntu 14.04 服务器,最好使用 SSH 密钥 以确保安全
- 设置一个 sudo 用户
- 验证您的内核版本
Docker 1.8.1 依赖于一些相当新的内核特性,因此请确保内核为 3.10 或更高版本。 一个新的映像将运行一个相当新的内核,但如果您需要检查,只需运行 uname -r
。
uname -r
我们在下面包含了一个新的 Ubuntu 14.04 Droplet 的输出,它超过了 3.10,所以除非你在 旧映像 上运行它,否则你不必担心任何事情。
Output3.13.0-57-generic
第 1 步 — 安装 Docker
Docker 托管一个启动脚本来让 Docker 在您的机器上启动并运行。 我们可以简单地运行命令:
sudo curl -sSL https://get.docker.com/ | sh
一般来说,您不应该将随机脚本从互联网传输到您的 shell ( | sh
),因为它们几乎可以做任何事情。 如果您想知道自己正在做什么,请查看 get.docker.com。
完成后,您将看到如下所示的已安装版本(您的读数可能较新;这很好)以及一些以非 root/无 sudo 身份运行的说明。 不过,我们以 sudo 用户的身份运行本教程,因此出于本教程的目的无需担心这一点。
Output Client: Version: 1.8.3 API version: 1.20 Go version: go1.4.2 Git commit: f4bf5c7 Built: Mon Oct 12 05:37:18 UTC 2015 OS/Arch: linux/amd64 Server: Version: 1.8.3 API version: 1.20 Go version: go1.4.2 Git commit: f4bf5c7 Built: Mon Oct 12 05:37:18 UTC 2015 OS/Arch: linux/amd64
可选:运行 hello-world
容器以确保一切按预期工作。
sudo docker run hello-world
您应该会看到类似于下图的输出。
Output $ docker run hello-world Unable to find image 'hello-world:latest' locally latest: Pulling from library/hello-world 535020c3e8ad: Pull complete af340544ed62: Already exists library/hello-world:latest: The image you are pulling has been verified. Important: image verification is a tech preview feature and should not be relied on to provide security. Digest: sha256:d5fbd996e6562438f7ea5389d7da867fe58e04d581810e230df4cc073271ea52 Status: Downloaded newer image for hello-world:latest Hello from Docker. This message shows that your installation appears to be working correctly. To generate this message, Docker took the following steps: 1. The Docker client contacted the Docker daemon. 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. 3. The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading. 4. The Docker daemon streamed that output to the Docker client, which sent it to your terminal. To try something more ambitious, you can run an Ubuntu container with: $ docker run -it ubuntu bash Share images, automate workflows, and more with a free Docker Hub account: https://hub.docker.com For more examples and ideas, visit: https://docs.docker.com/userguide/
完成后,我们就可以深入了解 Docker 的基础知识。
(可选)第 2 步 — 查看容器基础知识:运行、列出、删除
本节介绍如何运行基本容器,然后将其删除。 如果您已经知道如何使用 Docker,并且想跳到 Nginx 部分,请转到第 5 步。
我们已经安装了 Docker 客户端作为 Docker 安装的一部分,因此我们可以访问允许我们与容器交互的命令行工具。
如果我们运行以下命令;
sudo docker ps -a
您应该得到类似于以下内容的输出;
Output CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES a3b149c3ddea hello-world "/hello" 3 minutes ago Exited (0) 3 minutes ago nostalgic_hopper
我们可以看到一些关于我们容器的基本信息。
您会注意到它有一个荒谬的名称,例如 nostalgic_hopper
; 如果您在创建容器时未指定这些名称,则会自动生成这些名称。
我们还可以看到 hello-world
示例容器在 3 分钟前运行并在 3 分钟前退出。
如果我们用这个命令再次运行这个容器(用你自己的容器名称替换 nostalgic_hopper
):
sudo docker start nostalgic_hopper
然后运行命令列出容器:
sudo docker ps -a
我们现在应该看到容器最近运行过;
OutputCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES a3b149c3ddea hello-world "/hello" 4 minutes ago Exited (0) 9 seconds ago nostalgic_hopper
默认情况下,Docker 容器运行分配给它们的命令,然后退出。
一些容器将设置为通过任务列表运行并完成,而另一些容器将无限期运行。
现在我们已经了解了一些 Docker 基础知识,让我们删除 hello-world
映像,因为我们不再需要它(请记住将 nostalgic_hopper
替换为您的容器名称,或者使用您的容器ID)。
sudo docker rm nostalgic_hopper
接下来我们将开始使用 Nginx。
(可选)第 3 步 — 学习如何公开端口
在本节中,我们将下载 Nginx Docker 映像,并向您展示如何运行容器,以便将其作为 Web 服务器公开访问。
默认情况下,容器无法从 Internet 访问,因此我们需要将容器的 内部 端口映射到 Droplet 的端口。 这就是本节将教你的内容!
不过,首先,我们将获得 Nginx 映像。
第 5 步包含部署完整容器的最终命令,因此如果您不太关心实施细节,可以直接跳过那里。
运行以下命令获取 Nginx Docker 镜像:
sudo docker pull nginx
这将下载容器的所有必要组件。 Docker 会缓存这些,所以当我们运行容器时,我们不需要每次都下载容器镜像。
Docker 维护一个名为 Dockerhub 的站点,这是一个 Docker 文件(包括官方和用户提交的图像)的公共存储库。 我们下载的镜像是官方的 Nginx 镜像,这样我们就不必构建自己的镜像了。
让我们使用以下命令启动我们的 Nginx Docker 容器:
sudo docker run --name docker-nginx -p 80:80 nginx
run
是新建容器的命令--name
标志是我们指定容器名称的方式(如果为我们分配了一个空白,例如步骤 2 中的 nostalgic_hopper)-p
指定我们要暴露的端口,格式为-p local-machine-port:internal-container-port
。 在这种情况下,我们将容器中的端口 80 映射到服务器上的端口 80nginx
是 dockerhub 上的镜像名称(我们之前用 pull 命令下载了这个,但是如果镜像丢失,Docker 会自动执行此操作)
这就是我们启动 Nginx 所需的全部内容! 将您的 Droplet 的 IP 地址粘贴到 Web 浏览器中,您应该会看到 Nginx 的“欢迎使用 nginx!” 页。
您还会在 shell 会话中注意到,当您向服务器发出请求时,Nginx 的日志正在更新,因为我们正在交互式运行我们的容器。
让我们点击 break 快捷键 CTRL+C
回到我们的 shell 会话。
如果您现在尝试加载该页面,您将获得“连接被拒绝”页面。 这是因为我们关闭了容器。 我们可以使用以下命令验证这一点:
sudo docker ps -a
您应该会看到类似于下面显示的输出的内容。
OutputCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 05012ab02ca1 nginx "nginx -g 'daemon off" 57 seconds ago Exited (0) 47 seconds ago docker-nginx
我们可以看到我们的 Docker 容器已经退出。
如果我们需要将 Nginx 附加到容器映像以使其工作,那么 Nginx 将不会很有用,因此在下一步中,我们将向您展示如何分离容器以使其独立运行。
使用以下命令删除现有的 docker-nginx
容器:
sudo docker rm docker-nginx
在下一步中,我们将向您展示如何在分离模式下运行它。
(可选)第 4 步 — 学习如何在分离模式下运行
使用以下命令创建一个新的、分离的 Nginx 容器:
sudo docker run --name docker-nginx -p 80:80 -d nginx
我们添加了 -d
标志来在后台运行这个容器。
输出应该只是新容器的 ID。
如果我们运行 list 命令:
sudo docker ps
我们将在输出中看到一些我们以前从未见过的东西。
OutputCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES b91f3ce26553 nginx "nginx -g 'daemon off" About a minute ago Up About a minute 0.0.0.0:80->80/tcp, 443/tcp docker-nginx
我们可以看到现在有 Up About a minute
而不是 Exited (0) X minutes ago
,我们还可以看到端口映射。
如果我们在浏览器中再次访问我们服务器的 IP 地址,我们将能够看到“欢迎使用 nginx!” 再次页面。 这次它在后台运行,因为我们指定了 -d
标志,它告诉 Docker 以分离模式运行这个容器。
现在我们在一个分离的容器中有一个正在运行的 Nginx 实例!
但是,它还不够有用,因为我们无法编辑配置文件,并且容器无法访问我们的任何网站文件。
通过运行以下命令停止容器:
sudo docker stop docker-nginx
现在容器已停止(如果您想确定,可以使用 sudo docker ps -a
检查),我们可以通过运行以下命令将其删除;
sudo docker rm docker-nginx
现在我们将进入容器的最终版本,快速停止以生成自定义网站文件。
第 5 步 — 构建一个在 Nginx 上服务的网页
在这一步中,我们将为我们的网站创建一个自定义索引页面。 此设置允许我们拥有托管在(瞬态)容器之外的持久性网站内容。
让我们在主目录中为我们的网站内容创建一个新目录,并通过运行如下所示的命令移动到该目录。
mkdir -p ~/docker-nginx/html cd ~/docker-nginx/html
现在让我们创建一个 HTML 文件(我们展示了 Vim 的命令,但您可以使用任何您喜欢的文本编辑器)。
vim index.html
按 i
进入插入模式。 粘贴如下所示的内容(或随意添加您自己的 HTML 标记)。
<html> <head> <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet" integrity="sha256-MfvZlkHCEqatNoGiOXveE8FIwMzZg4W85qfrfIFBfYc= sha512-dTfge/zgoMYpP7QbHy4gWMEGsbsdZeCXz7irItjcC3sPUFtf0kuFbDz/ixG7ArTxmDjLXDmezHubeNikyKGVyQ==" crossorigin="anonymous"> <title>Docker nginx Tutorial</title> </head> <body> <div class="container"> <h1>Hello Digital Ocean</h1> <p>This nginx page is brought to you by Docker and Digital Ocean</p> </div> </body> </html>
如果您熟悉 HTML,您会发现这是一个超级基础的网页。 我们包含了一个 <link>
标签,它指向一个 CDN 用于 Bootstrap(一个 CSS 框架,为您的网页提供响应式样式的集合)。 您可以阅读有关 Bootstrap 的更多信息。
我们现在可以通过按 ESC
,然后按 :wq
和 ENTER
来保存这个文件:
- write (
w
) 告诉 Vim 将更改写入文件 - quit (
q
) 告诉 Vim 退出
我们现在有了一个简单的索引页面来替换默认的 Nginx 登录页面。
第 6 步 — 将容器链接到本地文件系统
在本节中,我们将把它们放在一起。 我们将启动 Nginx 容器,以便通过端口 80 在 Internet 上访问它,并将它连接到服务器上的网站内容。
有关卷的背景信息; 也就是说,从您的容器链接到永久服务器内容:
Docker 允许我们将目录从虚拟机的本地文件系统链接到我们的容器。
在我们的例子中,由于我们想要服务器网页,我们需要给我们的容器提供要渲染的文件。
我们可以将文件作为 Dockerfile 的一部分复制到容器中,或者在事后将它们复制到容器中,但这两种方法都会使我们的网站在容器内处于静态状态。 通过使用 Docker 的数据卷特性,我们可以在 Droplet 的文件系统和容器的文件系统之间创建符号链接。 这允许我们编辑现有的网页文件并将新的网页文件添加到目录中,我们的容器将自动访问它们。 如果您想了解更多关于 Docker 和卷的信息,请查看 数据卷文档 。
Nginx 容器默认设置为在 /usr/share/nginx/html
处查找索引页面,因此在我们的新 Docker 容器中,我们需要授予它访问该位置的文件的权限。
制作链接:
为此,我们使用 -v
标志将本地计算机 (~/docker-nginx/html
) 中的文件夹映射到容器中的相对路径 (/usr/share/nginx/html
)。
我们可以通过运行以下命令来完成此操作:
sudo docker run --name docker-nginx -p 80:80 -d -v ~/docker-nginx/html:/usr/share/nginx/html nginx
我们可以看到命令 -v ~/docker-nginx/html:/usr/share/nginx/html
的新增内容是我们的音量链接。
-v
指定我们正在链接一个卷:
左边的部分是我们的文件/目录在我们的虚拟机上的位置 (~/docker-nginx/html
):
右侧的部分是我们在容器中链接到的位置 (/usr/share/nginx/html
)
运行该命令后,如果您现在将浏览器指向 DigitalOcean Droplet 的 IP 地址,您应该会看到 Hello Digital Ocean 的第一个标题(或您在第 5 步中创建的任何网页)。
如果您对其他 Nginx 默认设置感到满意,则一切就绪。
您可以将更多内容上传到 ~/docker-nginx/html/
目录,它将添加到您的直播网站。
例如,如果我们修改我们的索引文件,并且如果我们重新加载我们的浏览器窗口,我们将能够看到它实时更新。 如果我们愿意,我们可以用这种方式用平面 HTML 文件构建一个完整的站点。 例如,如果我们添加了一个 about.html
页面,我们可以在 http://your_server_ip/about.html
访问它,而无需与容器交互。
(可选)第 7 步 — 使用您自己的 Nginx 配置文件
本部分适用于希望将自己的 Nginx 配置文件与 Nginx 容器一起使用的高级用户。 如果您没有要使用的自定义配置文件,请跳过此步骤。
让我们返回一个目录,这样我们就不会写入我们的公共 HTML 目录:
cd ~/docker-nginx
如果您想查看默认配置文件,只需使用 Docker 复制命令复制它:
sudo docker cp docker-nginx:/etc/nginx/conf.d/default.conf default.conf
由于我们将为 Nginx 使用自定义的 .conf
文件,因此我们需要重建容器。
首先停止容器:
sudo docker stop docker-nginx
删除它:
sudo docker rm docker-nginx
现在您可以在本地编辑默认文件(以提供新目录,或使用 proxy_pass
将流量转发到另一个应用程序/容器,就像使用常规 Nginx 安装一样)。 您可以在我们的 Nginx 配置文件指南 中了解 Nginx 的配置文件。
保存自定义配置文件后,就该创建 Nginx 容器了。 只需添加带有适当路径的第二个 -v
标志,即可为新的 Nginx 容器提供适当的链接以从您自己的配置文件运行。
sudo docker run --name docker-nginx -p 80:80 -v ~/docker-nginx/html:/usr/share/nginx/html -v ~/docker-nginx/default.conf:/etc/nginx/conf.d/default.conf -d nginx
此命令还在自定义网站页面中链接到容器。
请注意,如果在启动容器后对配置文件进行任何更改,则需要使用 docker restart
命令重新启动容器,因为如果更改了配置文件,Nginx 不会热重载:
sudo docker restart docker-nginx
结论
您现在有一个正在运行的 Nginx 容器服务于自定义网页。
从这里开始,我们建议阅读 Docker 的 container linking,如果您想了解如何将容器链接在一起,以便使用 Nginx 作为反向代理来为其他基于容器的 Web 应用程序提供服务。
如果你想管理一组容器,比如一个应用容器,一个数据库容器,还有这个 Nginx 容器,看看Docker Compose。