【问题标题】:Connect to docker container using hostname on local environment in kubernetes在 Kubernetes 的本地环境中使用主机名连接到 docker 容器
【发布时间】:2020-10-01 00:54:49
【问题描述】:

我有一个 kubernete docker-compose,其中包含

frontend - a web app running on port 80
backend - a node server for API running on port 80
database - mongodb

理想情况下,我希望通过http://frontend:80 等主机名访问frontend,并且浏览器能够通过http://backend:80 等主机名访问backend,这是网络应用程序所必需的在客户端。

如何让我的容器通过我的本地主机环境(Windows)上的这些主机名访问?


docker-compose.yml

version: "3.8"
services:
    frontend:
        build: frontend
        hostname: framework
        ports:
            - "80:80"
            - "443:443"
            - "33440:33440"
    backend:
        build: backend
        hostname: backend
    database:
        image: 'mongo'
        environment:
            - MONGO_INITDB_DATABASE=framework-database
        volumes:
            - ./mongo/mongo-volume:/data/database
            - ./mongo/init-mongo.js:/docker-entrypoint-initdb.d/init-mongo.js:ro
        ports:
            - '27017-27019:27017-27019'

【问题讨论】:

  • 是 Kubernetes 还是 Docker?浏览器应用程序通常在浏览器中运行,在这两种情况下都不在容器环境中,因此它永远不能使用 Compose 容器/Kubernetes 服务名称作为主机名。
  • @DavidMaze 它位于 docker-compose/kubernetes 容器中。我只想通过浏览器中的主机名(在容器环境之外)连接到容器
  • 你是如何暴露容器的?你有服务 yaml 吗?
  • @Bimal 我已经添加了我的 docker-compose
  • 看起来您的服务属于Cluster IP 类型。你能分享kubectl get svc的结果吗?

标签: docker kubernetes docker-compose dns


【解决方案1】:

我能够弄清楚,使用 docker-compose 别名和网络,我能够将每个容器连接到同一个开发网络。

有 3 个主要组成部分:

  • 容器映射节点 dns 服务器 - 通过 docker ps 获取别名并创建将这些请求重定向到 127.0.0.1 (localhost) 的 DNS 服务器
  • nginx 反向代理容器 - 通过虚拟网络中的别名将主机映射到容器
  • projects - 每个项目都是一个docker-compose.yml,可以在端口 80 上运行无限数量的容器

客户端 A 的 docker-compose.yml

version: "3.8"
services:
    frontend:
        build: frontend
        container_name: clienta-frontend
        networks:
            default:
                aliases:
                    - clienta.test
    backend:
        build: backend
        container_name: clienta-backend
        networks:
            default:
                aliases:
                    - api.clienta.test
networks:
    default:
        external: true # connect to external network (see below for more)
        name: 'development' # name of external network

nginx代理docker-compose.yml

version: '3'
services: 
    parent:
        image: nginx:alpine
        volumes:
            - ./nginx.conf:/etc/nginx/nginx.conf
        ports:
            - "80:80" #map port 80 to localhost
        networks:
            - development
networks:
    development: #create network called development
        name: 'development'
        driver: bridge

DNS 服务器

import dns from 'native-dns'
import { exec } from 'child_process'

const { createServer, Request } = dns
const authority = { address: '8.8.8.8', port: 53, type: 'udp' }
const hosts = {}

let server = createServer()

function command (cmd) {
    return new Promise((resolve, reject) => {
        exec(cmd, (err, stdout, stderr) => stdout ? resolve(stdout) : reject(stderr ?? err))
    })
}
async function getDockerHostnames(){
    let containersText = await command('docker ps --format "{{.ID}}"')
    let containers = containersText.split('\n')
    containers.pop()
    await Promise.all(containers.map(async containerID => {
        let json = JSON.parse(await command(`docker inspect ${containerID}`))?.[0]
        let aliases = json?.NetworkSettings?.Networks?.development?.Aliases || []
        aliases.map(alias => hosts[alias] = {
            domain: `^${alias}*`,
            records: [
                { type: 'A', address: '127.0.0.1', ttl: 100 }
            ]
        })
    }))
}

await getDockerHostnames()
setInterval(getDockerHostnames, 8000)

function proxy(question, response, cb) {
    var request = Request({
        question: question, // forwarding the question
        server: authority,  // this is the DNS server we are asking
        timeout: 1000
    })

    // when we get answers, append them to the response
    request.on('message', (err, msg) => {
        msg.answer.map(a => response.answer.push(a))
    });

    request.on('end', cb)
    request.send()
}

server.on('close', () => console.log('server closed', server.address()))
server.on('error', (err, buff, req, res) => console.error(err.stack))
server.on('socketError', (err, socket) => console.error(err))
server.on('request', async function handleRequest(request, response) {
    await Promise.all(request.question.map(question => {
        console.log(question.name)
        let entry = Object.values(hosts).find(r => new RegExp(r.domain, 'i').test(question.name))
        if (entry) {
            entry.records.map(record => {
                record.name = question.name;
                record.ttl = record.ttl ?? 600;
                return response.answer.push(dns[record.type](record));
            })
        } else {
            return new Promise(resolve => proxy(question, response, resolve))
        }
    }))

    response.send()
});

server.serve(53, '127.0.0.1');

不要忘记更新您的计算机网络设置以使用 127.0.0.1 作为 DNS 服务器

用于 dns 服务器 + nginx 代理的 Git 存储库,以防您想查看实现:https://github.com/framework-tools/dockerdnsproxy

【讨论】:

    猜你喜欢
    • 2015-11-28
    • 2020-01-20
    • 1970-01-01
    • 1970-01-01
    • 2021-08-15
    • 2017-06-13
    • 1970-01-01
    • 1970-01-01
    • 2020-09-04
    相关资源
    最近更新 更多