使用Docker部署NGINX和NGINX Plus

NGINX | 2021年11月09日


编辑注:NGINX Plus的Dockerfile(适用于Alpine Linux和Debian)已于2021年11月更新,以采用最新的软件版本。此外,在构建NGINX Plus镜像时,这些Dockerfile和修订后的说明还使用Docker Secret来传递许可证信息。

Docker是一个开放平台,可用于将分布式应用构建、交付并作为容器运行。容器是轻量级、独立且可执行的软件包,包含运行应用所需的一切。容器还可通过Kubernetes等容器编排平台进行部署和编排。(除了本博客介绍的Docker容器技术外,NGINX还提供F5 NGINX Ingress Controller,包括基于NGINX Open Source和基于NGINX Plus的版本;NGINX Plus订阅用户无需额外付费即可获得支持。)

作为软件应用,NGINX Open Source和F5 NGINX Plus都非常适合在Docker中使用。我们还在Docker镜像仓库NGINX Open Source镜像Docker Hub上发布了。本文将介绍如何:

简介

Docker开放平台包括Docker Engine(用于构建、运行和编排容器的开源运行时)和Docker Hub。Docker Hub是一项托管服务,整个开发者社区或特定组织内部可通过该服务分发、共享Docker化应用并开展协作。

Docker容器将应用与基础设施限制分离,使开发人员能够专注于应用“内容”。Docker化应用可即时移植到任何基础设施,包括笔记本电脑、裸机服务器、虚拟机或云环境,从而成为可轻松组装和重新组装的模块化组件,用于构建功能完备的分布式应用,并持续进行实时创新。

有关Docker的更多信息,请参阅为什么选择Docker?或完整的Docker文档。

使用NGINX Open Source Docker镜像

可以使用来自Docker Hub的NGINX Open Source镜像在Docker容器中创建NGINX实例。

先来看一个非常简单的示例。要启动一个在容器中运行并使用默认NGINX配置的NGINX实例,请运行以下命令:

# docker run --name mynginx1 -p 80:80 -d nginxfcd1fb01b14557c7c9d991238f2558ae2704d129cf9fb97bb4fadf673a58580d

此命令基于NGINX镜像创建一个名为mynginx1的容器。该命令会返回完整的容器ID,用于日志文件的命名;请参阅管理日志。

The -p选项指示Docker将NGINX镜像在容器中公开的端口(即端口80)映射到Docker主机上的指定端口。第一个参数指定Docker主机上的端口,第二个参数则映射到容器中公开的端口。

The -d选项指定容器以分离模式运行。这意味着容器会持续运行,直至被停止,但不会响应在命令行中运行的命令。下一节将介绍如何与容器交互。

要验证容器是否已创建并正在运行,并查看端口映射,请运行docker ps。(为便于阅读,此处将输出拆分为多行。)

# docker psCONTAINER ID  IMAGE         COMMAND               CREATED         STATUS        ...  
fcd1fb01b145  nginx:latest  "nginx -g 'daemon of  16 seconds ago  Up 15 seconds ... 

    ... PORTS              NAMES
    ... 0.0.0.0:80->80/tcp mynginx1

输出中的PORTS字段显示,Docker主机上的端口 80 已映射到容器中的端口 80。还可以通过向该端口发出HTTP请求来验证NGINX是否正在运行。随后会显示默认NGINX欢迎页面的代码:

# curl http://localhost<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
 body {
 width: 35em;
 margin: 0 auto;
 font-family: Tahoma, Verdana, Arial, sans-serif;
 }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="https://www.nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

使用NGINX Docker容器

现在,NGINX Docker容器已经可以正常运行,但该如何管理内容和NGINX配置?日志记录又该如何处理?

关于SSH的说明

通常会为NGINX实例启用SSH访问,但NGINX镜像未安装OpenSSH,因为Docker容器通常仅用于单一用途(在本例中为运行NGINX)。因此,我们将改用Docker支持的其他方法。

除了使用以下命令外,还可以运行下面的命令,为正在运行的NGINX容器打开交互式shell(而不是启动SSH会话)。不过,仅建议高级用户采用这种方式。

  • 在Alpine Linux系统上:
# docker exec -it NGINX_container_ID sh
  • 在Debian系统上:
# docker exec -it NGINX_container_ID bash

管理内容和配置文件

可以通过多种方式管理NGINX提供的内容和NGINX配置文件。下面介绍其中几种方式。

选项 1:在 Docker 主机上维护内容和配置

创建容器时,可以让Docker将Docker主机上的本地目录挂载到容器中的目录。NGINX镜像使用默认的NGINX配置,其中以/usr/share/nginx/html作为容器的根目录,并将配置文件放在/etc/nginx中。假设Docker主机的内容位于本地目录/var/www中,配置文件位于/var/nginx/conf中,请运行以下命令(此处仅为便于阅读而分多行显示):

# docker run --name mynginx2 --mount type=bind source=/var/www,target=/usr/share/nginx/html,readonly --mount type=bind,source=/var/nginx/conf,target=/etc/nginx/conf,readonly -p 80:80 -d nginx

现在,对Docker主机上本地目录/var/www和/var/nginx/conf中文件所做的任何更改,都会反映到容器内的目录/usr/share/nginx/html和/etc/nginx中。readonly选项表示这些目录只能在Docker主机上更改,不能从容器内更改。

选项 2:从 Docker 主机复制文件

另一种方法是在创建容器时,让Docker从Docker主机上的本地目录复制内容和配置文件。容器创建后,如果文件发生更改,可以创建新容器或直接修改容器中的文件来维护这些文件。复制文件的一种简单方法是创建一个Dockerfile,其中包含基于Docker Hub中的NGINX镜像生成新Docker镜像时运行的命令。对于Dockerfile中的文件复制(COPY)命令,本地目录路径是相对于Dockerfile所在的构建上下文而言的。

在本例中,内容位于content目录中,配置文件位于conf目录中。这两个目录都是Dockerfile所在目录的子目录。NGINX镜像包含以下默认NGINX配置文件:/etc/nginx/nginx.conf和/etc/nginx/conf.d/default.conf。由于我们希望改用主机中的配置文件,因此添加一条RUN命令来删除默认文件:

FROM nginx
RUN rm /etc/nginx/nginx.conf /etc/nginx/conf.d/default.conf
COPY content /usr/share/nginx/html
COPY conf /etc/nginx

在Dockerfile所在目录中运行以下命令,创建自定义NGINX镜像。请注意命令末尾的句点(“.”)。该句点将当前目录指定为构建上下文,其中包含Dockerfile以及要复制的目录。

# docker build -t mynginx_image1 .

现在运行以下命令,创建一个名为mynginx3的容器,该容器基于mynginx_image1镜像:

# docker run --name mynginx3 -p 80:80 -d mynginx_image1

如果要修改容器中的文件,请按照选项 3 中的说明使用辅助容器。

选项3:维护容器中的文件

如关于SSH的说明中所述,我们无法使用SSH访问NGINX容器。因此,如果要直接编辑内容文件或配置文件,就必须创建一个可通过shell访问的辅助容器。要让辅助容器访问这些文件,必须创建一个新镜像,并为该镜像正确定义Docker数据卷。假设要像选项2一样复制文件,同时定义卷,可使用以下Dockerfile:

FROM nginxRUN rm /etc/nginx/nginx.conf /etc/nginx/conf.d/default.conf
COPY content /usr/share/nginx/html
COPY conf /etc/nginx
VOLUME /usr/share/nginx/html
VOLUME /etc/nginx

然后,运行以下命令创建新的NGINX镜像(同样请注意末尾的句点):

# docker build -t mynginx_image2 .

现在运行以下命令,基于mynginx4镜像创建一个NGINX容器(mynginx_image2):

# docker run --name mynginx4 -p 80:80 -d mynginx_image2

然后运行以下命令,启动一个带有shell的辅助容器mynginx4_files,以便访问刚刚创建的mynginx4容器中的内容目录和配置目录:

# docker run -i -t --volumes-from mynginx4 --name mynginx4_files debian /bin/bashroot@b1cbbad63dd1:/#

新的mynginx4_files辅助容器在前台运行,并保持标准输入持续打开(使用-i选项),同时分配一个tty(使用-t选项)。在mynginx4中定义的所有卷都会作为本地目录挂载到该辅助容器中。

The debian 参数表示辅助容器使用Docker Hub中的Debian镜像。由于NGINX镜像也使用Debian(而且目前为止的所有示例都使用NGINX镜像),因此让辅助容器使用Debian效率更高,无需Docker加载其他操作系统。/bin/bash 参数表示在辅助容器中运行 bash shell,并显示shell提示符,以便根据需要修改文件。

要启动和停止容器,请运行以下命令:

# docker start mynginx4_files# docker stop mynginx4_files

要退出shell但让容器继续运行,请按Ctrl+p,然后按Ctrl+q。要重新访问正在运行的容器的shell,请运行以下命令:

# docker attach mynginx4_files

要退出shell并终止容器,请运行exit命令。

管理日志记录

您可以配置默认日志记录或自定义日志记录。

使用默认日志记录

默认情况下,NGINX镜像配置为将主要的NGINX访问日志和错误日志发送到Docker日志收集器。具体做法是分别将这两类日志链接到stdout和stderr;随后,这两类日志中的所有消息都会写入Docker主机上的文件/var/lib/docker/containers/container-ID/container-ID-json.log,其中container‑ID是创建容器时返回的长格式ID。例如,对于我们在使用NGINX Open Source Docker镜像中创建的初始容器,其ID为fcd1fb01b14557c7c9d991238f2558ae2704d129cf9fb97bb4fadf673a58580d。

要获取现有容器的容器ID,请运行以下命令。其中,container‑name是创建容器时通过--name参数设置的值(例如,对于上述容器ID,该值为mynginx1):

# docker inspect --format '{{ .Id }}' container-name

虽然可以直接打开container-ID-json.log文件查看日志,但运行以下命令通常更方便:

# docker logs container-name

还可以使用Docker Engine API提取日志消息,方法是向Docker Unix套接字发送GET请求。此命令会同时返回访问日志(以stdout=1表示)和错误日志(以stderr=1表示),也可以单独请求其中任一日志:

curl --unix-socket /var/run/docker-sock http://localhost/containers/container-name/logs?stdout=1&stderr=1

要了解其他查询参数,请参阅Docker Engine API 文档(在该页面中搜索“Get container logs”)。

使用自定义日志记录

如果要采用其他日志收集方法,或要在某些配置块(例如server{}和location{})中以不同方式配置日志,请为容器内用于存储日志文件的一个或多个目录定义Docker卷,创建一个辅助容器来访问日志文件,并使用所需的日志记录工具。为此,请创建一个包含日志文件所用卷的新镜像。

例如,要将NGINX配置为在/var/log/nginx/log中存储日志文件,可以从Dockerfile(参见选项3)入手,只需为此目录添加VOLUME定义:

FROM nginxRUN rm /etc/nginx/nginx.conf /etc/nginx/conf.d/default.conf
COPY content /usr/share/nginx/html
COPY conf /etc/nginx
VOLUME /var/log/nginx/log

然后,可以按上述说明创建镜像,并使用该镜像创建一个NGINX容器和一个可访问日志目录的辅助容器。辅助容器中可以安装所需的任何日志记录工具。

控制NGINX

由于无法直接访问NGINX容器的命令行,因此不能使用nginx命令控制NGINX。所幸,可以使用信号控制NGINX,而Docker提供了kill命令,用于向容器发送信号。

要重新加载NGINX配置,请运行以下命令:

# docker kill -s HUP container-name

要重启NGINX,请运行以下命令来重启容器:

# docker restart container-name

使用Docker部署NGINX Plus

到目前为止,我们讨论了如何将Docker用于NGINX Open Source,但Docker也可与商业产品NGINX Plus配合使用。不同之处在于,您首先需要创建NGINX Plus镜像,因为NGINX Plus是商业产品,无法从Docker Hub获取。好在创建镜像非常简单。

注意:切勿将NGINX Plus镜像上传到Docker Hub等公共存储库。这样做会违反许可协议。

创建NGINX Plus Docker镜像

要生成NGINX Plus镜像,请先创建一个Dockerfile。此处提供的示例使用Alpine Linux 3.14和Debian 11(Bullseye)作为Docker基础镜像。创建NGINX Plus Docker镜像之前,必须下载与所用版本对应的nginx-repo.crt和nginx-repo.key文件。NGINX Plus客户可在客户门户中找到这些文件;如果正在免费试用NGINX Plus,这些文件已随试用包提供。请将这些文件复制到Dockerfile所在的目录(Docker构建上下文)中。

与NGINX Open Source一样,默认情况下,NGINX Plus访问日志和错误日志会链接到Docker日志收集器。此处未指定卷,但可根据需要添加;也可以使用每个Dockerfile创建基础镜像,再基于这些基础镜像创建指定了卷的新镜像,如前文所述。

我们特意未在示例Dockerfile中指定NGINX Plus版本,因此更新到NGINX Plus的新版本时,无需编辑该文件。不过,我们提供了相关指令的注释版本。如果希望该文件仅适用于特定版本,可以取消这些指令的注释。

同样,我们还提供了用于安装NGINX Plus官方动态模块的指令(已注释掉)。

默认情况下,创建容器时不会从Docker主机复制任何文件。可以向每个COPYDockerfile中添加定义,也可以按照上述说明,将创建的镜像用作其他镜像的基础。

NGINX Plus Dockerfile(Debian 11)

正在加载代码示例…

NGINX Plus Dockerfile(Alpine Linux 3.14)

正在加载代码示例…

创建NGINX Plus镜像

将Dockerfile、nginx-repo.crt和nginx-repo.key文件放在同一目录中,然后在该目录中运行以下命令,创建名为nginxplus的Docker镜像(与之前一样,请注意末尾的句点):

# DOCKER_BUILDKIT=1 docker build --no-cache -t nginxplus --secret id=nginx-crt,src=your_cert_file --secret id=nginx-key,src=your_key_file .

The DOCKER_BUILDKIT=1标志表示使用Docker BuildKit构建镜像;添加下文所述的--secret选项时,必须使用该工具。

The --no-cache选项指示Docker从头开始构建镜像,并确保安装最新版本的NGINX Plus。如果此前曾使用Dockerfile构建镜像,但未添加--no-cache选项,则新镜像会使用Docker缓存中的NGINX Plus版本。(如前所述,我们特意未在Dockerfile中指定NGINX Plus版本,因此无需在NGINX Plus每次发布新版本时更改该文件。)如果可以接受使用此前所构建镜像中的NGINX Plus版本,则可省略--no-cache选项。

The --secret选项会将NGINX Plus许可证的证书和密钥传递到Docker构建上下文,同时避免数据泄露或在Docker构建层之间持久保留。若不修改基础id参数的值,则无法更改Dockerfile,但需要将src参数设置为NGINX Plus证书和密钥文件的路径(如果已按照前述说明操作,即构建Docker镜像的同一目录)。

执行docker images nginxplus 命令后,如果显示类似以下内容,则表示镜像已成功创建:

# docker images nginxplus
REPOSITORY  TAG     IMAGE ID      CREATED        VIRTUAL SIZE
nginxplus   latest  ef2bf65931cf  6 seconds ago  91.2 MB

要基于此镜像创建名为“mynginxplus”的容器,请运行以下命令:

# docker run --name mynginxplus -p 80:80 -d nginxplus

可以像控制和管理NGINX Open Source容器一样控制和管理NGINX Plus容器。

总结

NGINX、NGINX Plus和Docker可以高效协同工作。无论是使用Docker Hub上的NGINX Open Source镜像,还是自行创建NGINX Plus镜像,都可以轻松在Docker容器中启动新的NGINX和NGINX Plus实例,并将其部署到Kubernetes环境中。还可以基于基础镜像轻松创建新的Docker镜像,让容器更易于控制和管理。请确保Docker容器中运行的所有NGINX Plus实例均在订阅涵盖范围内。有关详细信息,请联系NGINX销售团队。

Docker涉及的内容远不止本文所能涵盖。要了解更多信息,请下载我们的免费O’Reilly电子书《容器网络:从Docker到Kubernetes》,或访问www.docker.com。

相关文档

在Docker上部署NGINX和NGINX Plus


分享
标签: F5 NGINX, 2021, Tech

关于作者

Rick Nelson
Rick Nelson解决方案工程区域副总裁

Rick Nelson 的更多博客文章

相关博客文章

NGINX Plus R26 正式发布
NGINX | 2022/02/15

NGINX Plus R26 正式发布

NGINX Plus R26通过缓存JSON Web密钥集加快JWT验证,并强化TLS握手,从而提升安全性。NGINX JavaScript的新功能包括增强对异步函数的支持,以及实现WebCrypto API。

使用NGINX App Protect DoS保护gRPC应用,抵御严重的DoS攻击
NGINX | 2022/02/10

使用NGINX App Protect DoS保护gRPC应用,抵御严重的DoS攻击

gRPC具备开发人员设计和部署现代应用所需的速度与灵活性,但其开放性也使其极易受到第7层DoS攻击。NGINX App Protect DoS可保护gRPC应用免受此类破坏性攻击。

Ingress Controller 选型指南(第 2 部分):风险与面向未来的规划
NGINX | 2021/09/13

Ingress Controller 选型指南(第 2 部分):风险与面向未来的规划

了解选择错误的Ingress控制器可能带来的风险,以及如何从关键方面着手,让您的选择更好地适应未来需求。

NGINX Plus R19 正式发布
NGINX | 2019/09/03

NGINX Plus R19 正式发布

NGINX Plus R19扩展了监控功能,不仅提供更多指标,还新增了指标分析方式;增加试运行模式,用于测试限速效果;增强键值存储,以支持IP地址范围;并使限速更加动态。

NGINX现已正式加入F5
NGINX | 2019/05/09

NGINX现已正式加入F5

NGINX现已正式成为F5的一部分。Gus Robertson现任F5 NGINX业务部门负责人。他阐述了两家公司在人才、文化和愿景方面融合的价值,以及双方将如何携手增强NGINX的开源产品和商业产品。

使用NGINX和NGINX Plus实现高性能缓存
NGINX | 2016/08/24

使用NGINX和NGINX Plus实现高性能缓存

我将介绍NGINX在内容缓存和性能方面的工作原理,并分享一些控制NGINX内容缓存方式的技巧。