Kamal部署报错:host settings conflict with another service 求助
我正在使用Kamal 2部署nextjs-golang-crud-app项目。后端容器(端口8080)部署成功后,执行kamal setup部署前端(端口3000),两者均处于kamal docker桥接网络,通过kamal-proxy容器暴露服务。
部署时出现如下错误:
ERROR (SSHKit::Command::Failed): Exception while executing on host localhost: docker exit status: 1
docker stdout: Nothing written
docker stderr: Error: host settings conflict with another service
exit status 1
前后端可独立部署,推测冲突原因是两者都通过kamal-proxy的80端口暴露,导致代理无法路由流量。
前端kamal部署配置
service: ngca-frontend image: hunger1607/ngca-frontend servers: - 127.0.0.1 ssh: keys: [~/abel-ec2-keypair.pem] user: ubuntu registry: username: - DOCKER_REGISTRY_USERNAME password: - DOCKER_REGISTRY_PASSWORD builder: arch: - amd64 dockerfile: Dockerfile env: clear: PORT: "3000" proxy: app_port: 3000 response_timeout: 120 healthcheck: interval: 5 path: / timeout: 60
后端kamal部署配置
service: ngca-backend image: hunger1607/ngca-backend servers: - 127.0.0.1 ssh: keys: [~/abel-ec2-keypair.pem] user: ubuntu keys_only: true registry: username: - DOCKER_REGISTRY_USERNAME password: - DOCKER_REGISTRY_PASSWORD builder: arch: - amd64 dockerfile: Dockerfile env: clear: API_PORT: "8080" DB_PORT: "5432" DB_USER: "postgres" DB_PASS: "postgres" DB_NAME: "postgres" DB_HOST: "ngca-backend-db" accessories: db: image: postgres:15 host: ubuntu@localhost port: 5432 env: clear: POSTGRES_USER: postgres POSTGRES_DB: postgres secret: - POSTGRES_PASSWORD proxy: app_port: 8080 response_timeout: 210 healthcheck: interval: 5 path: /swagger/index.html timeout: 300
报错原因分析
你的推测完全正确:默认情况下,Kamal为每个部署的服务都会创建独立的kamal-proxy容器,两个代理容器都试图绑定主机的80端口,导致端口资源冲突,触发host settings conflict with another service错误。
解决方法
有两种可行方案解决该问题:
方案1:共享同一个Kamal代理(推荐)
让前后端服务共享同一个kamal-proxy,通过路径前缀区分流量路由,更符合生产环境的部署逻辑:
- 移除前端配置中的
proxy块,仅保留后端的proxy配置。 - 修改后端的
proxy配置,添加路由规则,将不同路径转发到对应服务:proxy: app_port: 8080 response_timeout: 210 healthcheck: interval: 5 path: /swagger/index.html timeout: 300 routes: - path: "/" service: ngca-frontend:3000 - path: "/api" service: ngca-backend:8080 - 确保前后端服务处于同一Kamal网络(默认会自动加入以服务名命名的网络,无需额外配置)。
方案2:为其中一个代理指定不同的主机端口
如果需要保持独立代理,可以修改其中一个服务的proxy配置,指定非80的主机端口:
比如修改前端的proxy块:
proxy: app_port: 3000 host_port: 8081 # 指定新的主机端口 response_timeout: 120 healthcheck: interval: 5 path: / timeout: 60
修改后,前端通过http://localhost:8081访问,后端通过http://localhost:80访问,避免端口冲突。
内容的提问来源于stack exchange,提问作者Abel Tesfaye

