我看到很多帖子使用 traefik 在 docker 群中实现了 Tomcat 会话复制。但我只是不想添加另一个组件。我使用 httpd 作为 tomcat 的前端。Tomcat 将部署为具有 4 个副本的服务,并将在需要时进行扩展。httpd 作为 docker 服务运行,两者位于同一网络中。我的问题是,在这种情况下,有没有办法在 docker 群中实现 Tomcat 会话复制。蒂亚。
只要所有 Tomcat Docker 容器都可以访问,就可以通过下面的集群设置来实现这一点。
以下设置适用于 tomcat 7,但对于其他版本也应该以相同的方式工作。
如果是Apache Tomcat 7,请取消注释<Cluster className=”org.apache.catalina.ha.tcp.SimpleTcpCluster”/>
标记并更新集群详细信息,如下所示。
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster">
<Manager className="org.apache.catalina.ha.session.DeltaManager"
expireSessionsOnShutdown="false"
notifyListenersOnReplication="true"/>
<Channel className="org.apache.catalina.tribes.group.GroupChannel">
<Membership className="org.apache.catalina.tribes.membership.McastService"
address="228.0.0.4"
port="45564" frequency="500"
dropTime="3000"/>
<Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
<Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>
</Sender>
<Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
address="auto" port="4000" autoBind="100"
selectorTimeout="5000" maxThreads="6"/>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.ThroughputInterceptor"/>
</Channel>
<Valve className="org.apache.catalina.ha.tcp.ReplicationValve" />
<ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener" />
</Cluster>
此外,我们需要apache/conf/
路径添加workers.properties
。
请注意,此文件必须放置在将在集群中运行的所有Tomcat服务器中。
您可以在此处阅读更多详细信息。
您可以在没有前端的情况下执行此操作,但是您会遇到问题,因为如果入口路由到其他节点,则该节点必须从另一个节点请求会话。
普通的雄猫映像不足以进行群集,它需要一些自定义来/usr/local/tomcat/conf/server.xml
群集配置以使用该DNSMembershipProvider
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster">
<Channel className="org.apache.catalina.tribes.group.GroupChannel">
<Membership
className="org.apache.catalina.tribes.membership.cloud.CloudMembershipService"
membershipProviderClassName="org.apache.catalina.tribes.membership.cloud.DNSMembershipProvider"
/>
</Channel>
</Cluster>
DNSMembershipProvider
使用环境变量DNS_MEMBERSHIP_SERVICE_NAME
来查找服务器,使其应与服务名称匹配。
以下docker-compose.yml
演示如何在没有任何其他组件的情况下部署它。
version: "3.8"
services:
tomcat:
build: ./tomcat
image: sample-tomcat
environment:
- DNS_MEMBERSHIP_SERVICE_NAME=tomcat
ports:
- 50000:80
deploy:
replicas: 6
update_config:
order: start-first
正确的方式
如前所述,使用上述方法将满足OP不添加额外组件的要求,但会产生严重的性能问题。 相反,您需要一个可以路由到具有以下功能的服务器的代理:
- 会话粘性
- 码头工人群服务标签发现
- 运行状况检查通过事先检测服务器关闭来减少潜在的用户影响。
Traefik 可以很好地处理所有要求,即使它不支持集群,因为他们的 ACME 存储不允许并发访问而不转到他们的 EE 版本。
docker-compose.yml
如下。
version: "3.8"
services:
proxy:
image: traefik:2.6
command:
- "--providers.docker.swarmMode=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.app.address=:80"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
ports:
- 50000:80
tomcat:
build: ./tomcat
image: sample-tomcat
environment:
- DNS_MEMBERSHIP_SERVICE_NAME=tomcat
deploy:
replicas: 6
labels:
- "traefik.enable=true"
- "traefik.http.routers.app.entrypoints=app"
- "traefik.http.routers.app.rule=Host(`localhost`)"
- "traefik.http.services.app-service.loadBalancer.sticky.cookie=true"
- "traefik.http.services.app-service.loadBalancer.sticky.cookie.httponly=true"
- "traefik.http.services.app-service.loadbalancer.server.port=8080"
- "traefik.http.services.app-service.loadbalancer.healthcheck.path=/"
update_config:
order: start-first
endpoint_mode: dnsrr
一个需要注意的属性是endpoint_mode: dnsrr
之前公开端口时不可用。 这样可以更好地复制 Tomcat 集群中的会话数据,因为每个节点都有单独的 ID。
一个示例实现在我的 github 存储库中 https://github.com/trajano/tomcat-docker-swarm