Docker 化托管在 EC2 上的多个 Web 应用程序:优化容器大小和处理端口
Dockerizing multiple web applications hosted on EC2: Optimizing container size, and handling ports
我的雇主有兴趣使用 Docker 来容器化他们的 Web 应用程序。我们使用 AWS EC2 来托管我们的应用程序,它运行 Tomcat 服务多个 WARs。我是 Docker 的新手,需要弄清楚如何最好地处理这个问题。
据我了解,拥有一个 Docker 容器 运行 多个 Web 应用程序是不合适的。因此,对于每个应用程序,我应该从 Tomcat 基础映像构建一个容器,然后将 WAR 复制到 tomcat/webapps 目录,就像在 Docker 文件中一样:
FROM tomcat:9.0.44-jdk11-openjdk
COPY ./target/my-app-1.00-SNAPSHOT.war $CATALINA_HOME/webapps/my-app.war
足够简单,工作正常。但是 Tomcat 图像是 440MB。因此,如果我们目前有 Tomcat 运行 5 WAR 个文件,每个文件大小为 50 MB 左右,并且每个文件都有自己的容器 运行 Tomcat,我们'我们正在考虑将每个应用程序的大小增加十倍。那似乎……真的很低效。这真的是使用 Docker 个容器的成本吗?我怎样才能最大限度地减少这种情况?
我也不确定如何处理端口。现在端口 8080 映射到 subdomain.mydomain.com。但是每个容器显然会 运行 在不同的端口上。假设我在端口 8080 上为 my-app-1 启动了一个容器,在 8081 上为 my-app-2 启动了一个容器。我怎样才能让用户简单地导航到 subdomain.mydomain.com/my-app-1,和 subdomain.mydomain.com/my-app-2?
磁盘存储
一个Docker图像基本上是一个层列表(参见specification) mounted using a union filesystem (usually overlay2),这大大减少了所需的物理存储量。下层是只读的,可以在容器之间共享。
对于 5 个不同的应用程序,您只需要 50 * 5 + 440 MiB。与您当前配置的唯一区别是大约 50 MiB 的 Debian 映像(参见 repo info)。您可以通过将应用程序中使用的公共库导出到 Tomcat 的公共类加载器并创建应用程序共享的 Docker 图像来进一步减少它:无论如何每个 Tomcat 都会有一个应用程序, 因此保证了应用程序之间的隔离。
内存
与您当前配置的主要区别在于内存消耗:您将拥有 5 个 JVM 运行ning + Tomcat 的库。
网络配置
在内部,每个容器都将监听相同的端口,但在不同的私有地址上(附加到虚拟网络设备,参见networking)。 Docker 可以配置从主机系统上的端口到 docker 容器的端口转发 (NAT),但这只有在您想直接访问 时才有用来自 Internet 的容器中的服务 运行ning。
在您的情况下,您宁愿需要 运行 在主机系统上 反向代理 ,例如 NGINX 或 Apache Http 服务器。这将为您的 URL 命名空间提供相当于一个联合文件系统。
反向代理的选择是个人喜好问题:
- Apache2 可以使用 AJP 协议(通过
mod_jk
或更新的 mod_proxy_ajp
模块),无需任何配置即可将客户端连接的每个细节转发给 Tomcat。
- NGINX 更小并且只使用 HTTP,因此您需要配置
RemoteIpValve
和 SSLValve
.
然而,AJP 正在慢慢被 Tomcat 放弃,转而支持纯 HTTP(参见 this talk)。
完全同意@Piotr P. Karwasz
。只是想指出,既然现在你必须管理多个容器,你可能想利用 docker-compose:
version: '3.3'
services:
app1:
build: ./app1 # expose nothing, reverse proxy will have access to the host via docker-internal vnet
app2:
build: ./app2 # expose nothing, reverse proxy will have access to the host via docker-internal vnet
proxy:
image: nginx
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro # config is pretty minimal, but I'll include it below for completeness
ports:
- 8081:80 # nginx entry point
# nginx config
worker_processes 2;
events {
use epoll;
worker_connections 128;
}
http {
server {
server_name localhost;
listen 0.0.0.0:80;
location /app1 {
proxy_pass http://app1:8080/my-app/;
}
location /app2 {
proxy_pass http://app2:8080/my-app/;
}
}
}
那么每个应用程序都会有自己的子目录和一个 Dockerfile
正如您所概述的那样
关于反向代理的更多信息
除了 NGINX,您可能还想考虑 Traefik。它提供了有趣的功能,例如容器自动发现和 Let's Encrypt 支持:
proxy:
image: traefik
command: --api.insecure=true --providers.docker
ports:
- 8081:80 # Traefik entry point
- 8080:8080 # management UI, you probably don't want this exposed in production
volumes:
- /var/run/docker.sock:/var/run/docker.sock
我的雇主有兴趣使用 Docker 来容器化他们的 Web 应用程序。我们使用 AWS EC2 来托管我们的应用程序,它运行 Tomcat 服务多个 WARs。我是 Docker 的新手,需要弄清楚如何最好地处理这个问题。
据我了解,拥有一个 Docker 容器 运行 多个 Web 应用程序是不合适的。因此,对于每个应用程序,我应该从 Tomcat 基础映像构建一个容器,然后将 WAR 复制到 tomcat/webapps 目录,就像在 Docker 文件中一样:
FROM tomcat:9.0.44-jdk11-openjdk
COPY ./target/my-app-1.00-SNAPSHOT.war $CATALINA_HOME/webapps/my-app.war
足够简单,工作正常。但是 Tomcat 图像是 440MB。因此,如果我们目前有 Tomcat 运行 5 WAR 个文件,每个文件大小为 50 MB 左右,并且每个文件都有自己的容器 运行 Tomcat,我们'我们正在考虑将每个应用程序的大小增加十倍。那似乎……真的很低效。这真的是使用 Docker 个容器的成本吗?我怎样才能最大限度地减少这种情况?
我也不确定如何处理端口。现在端口 8080 映射到 subdomain.mydomain.com。但是每个容器显然会 运行 在不同的端口上。假设我在端口 8080 上为 my-app-1 启动了一个容器,在 8081 上为 my-app-2 启动了一个容器。我怎样才能让用户简单地导航到 subdomain.mydomain.com/my-app-1,和 subdomain.mydomain.com/my-app-2?
磁盘存储
一个Docker图像基本上是一个层列表(参见specification) mounted using a union filesystem (usually overlay2),这大大减少了所需的物理存储量。下层是只读的,可以在容器之间共享。
对于 5 个不同的应用程序,您只需要 50 * 5 + 440 MiB。与您当前配置的唯一区别是大约 50 MiB 的 Debian 映像(参见 repo info)。您可以通过将应用程序中使用的公共库导出到 Tomcat 的公共类加载器并创建应用程序共享的 Docker 图像来进一步减少它:无论如何每个 Tomcat 都会有一个应用程序, 因此保证了应用程序之间的隔离。
内存
与您当前配置的主要区别在于内存消耗:您将拥有 5 个 JVM 运行ning + Tomcat 的库。
网络配置
在内部,每个容器都将监听相同的端口,但在不同的私有地址上(附加到虚拟网络设备,参见networking)。 Docker 可以配置从主机系统上的端口到 docker 容器的端口转发 (NAT),但这只有在您想直接访问 时才有用来自 Internet 的容器中的服务 运行ning。
在您的情况下,您宁愿需要 运行 在主机系统上 反向代理 ,例如 NGINX 或 Apache Http 服务器。这将为您的 URL 命名空间提供相当于一个联合文件系统。
反向代理的选择是个人喜好问题:
- Apache2 可以使用 AJP 协议(通过
mod_jk
或更新的mod_proxy_ajp
模块),无需任何配置即可将客户端连接的每个细节转发给 Tomcat。 - NGINX 更小并且只使用 HTTP,因此您需要配置
RemoteIpValve
和SSLValve
.
然而,AJP 正在慢慢被 Tomcat 放弃,转而支持纯 HTTP(参见 this talk)。
完全同意@Piotr P. Karwasz
。只是想指出,既然现在你必须管理多个容器,你可能想利用 docker-compose:
version: '3.3'
services:
app1:
build: ./app1 # expose nothing, reverse proxy will have access to the host via docker-internal vnet
app2:
build: ./app2 # expose nothing, reverse proxy will have access to the host via docker-internal vnet
proxy:
image: nginx
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro # config is pretty minimal, but I'll include it below for completeness
ports:
- 8081:80 # nginx entry point
# nginx config
worker_processes 2;
events {
use epoll;
worker_connections 128;
}
http {
server {
server_name localhost;
listen 0.0.0.0:80;
location /app1 {
proxy_pass http://app1:8080/my-app/;
}
location /app2 {
proxy_pass http://app2:8080/my-app/;
}
}
}
那么每个应用程序都会有自己的子目录和一个 Dockerfile
正如您所概述的那样
关于反向代理的更多信息
除了 NGINX,您可能还想考虑 Traefik。它提供了有趣的功能,例如容器自动发现和 Let's Encrypt 支持:
proxy:
image: traefik
command: --api.insecure=true --providers.docker
ports:
- 8081:80 # Traefik entry point
- 8080:8080 # management UI, you probably don't want this exposed in production
volumes:
- /var/run/docker.sock:/var/run/docker.sock