読者です 読者をやめる 読者になる 読者になる

はわわーっ

はわわわわっ

nginxでダイナミックにリバースプロキシするやつ

nginx docker

SD12月号のdocker特集にあったやつ。
ngixnxをリバースプロキシとして目的のdockerのコンテナにプロキシする。
dockerのコンテナの管理とかはfig使った。

meu@u01:~/docker/dproxy$ find . -type f
./linkd/Dockerfile
./linkd/linkd
./fig.yml
./redis/Dockerfile
./redis/redis.conf
./nginx/Dockerfile
./nginx/nginx.conf
meu@u01:~/docker/dproxy$ cat fig.yml 
nginx:
  build: nginx
  command: /usr/sbin/nginx
  ports:
    - "80:80"
  links:
    - redis

redis:
  build: redis
  command: /usr/bin/redis-server /etc/redis/redis.conf
  expose:
    - "6379"

linkd:
  build: linkd
  command: /usr/bin/linkd
  links:
    - redis
  environment:
    DOCKER_HOST: 192.168.56.102:2375
meu@u01:~/docker/dproxy$ cat nginx/Dockerfile 
FROM ubuntu:trusty

RUN apt-get update -y && apt-get dist-upgrade -fy
RUN apt-get install -fy lua-nginx-redis nginx-extras
ADD nginx.conf /etc/nginx/nginx.conf
meu@u01:~/docker/dproxy$ cat nginx/nginx.conf 
user www-data;
daemon off;

env REDIS_PORT_6379_TCP_ADDR;
env REDIS_PORT_6379_TCP_PORT;

events {
        worker_connections 768;
}

http {
        include /etc/nginx/mime.types;
        default_type application/octet-stream;

        access_log /var/log/nginx/access.log;
        error_log /var/log/nginx/error.log;

        server {
                listen 80 default_server;
                root /usr/share/nginx/html;
                index index.html index.htm;

                location / {
                        set $forward "";

                        rewrite_by_lua '
                                local redis = require "nginx.redis"
                                local client = redis:new()
                                local redishost = os.getenv("REDIS_PORT_6379_TCP_ADDR")
                                local redisport = os.getenv("REDIS_PORT_6379_TCP_PORT")
                                local ok, _ = client:connect(redishost, redisport)
                                if not ok then
                                        ngx.exit(ngx.HTTP_SERVICE_UNAVAILABLE)
                                end
                                local sub, _ = string.gsub(ngx.var.host, "([^%.]+)%..*", "%1")
                                local res, err = client:get(sub)
                                if err then
                                        ngx.exit(ngx.HTTP_SERVICE_UNAVAILABLE)
                                end
                                if res == ngx.null then
                                        ngx.exit(ngx.HTTP_NOT_FOUND)
                                end
                                ngx.var.forward = res
                        ';

                        proxy_set_header Host $host;
                        proxy_set_header X-Real-IP $remote_addr;
                        proxy_set_header X-Forwarded-Host $host;
                        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                        proxy_set_header X-Forwarded-Proto $scheme;
                        proxy_pass http://$forward;
                }
        }
}
meu@u01:~/docker/dproxy$ cat redis/Dockerfile 
FROM ubuntu:trusty

RUN apt-get update -y && apt-get dist-upgrade -fy
RUN apt-get install -fy redis-server
ADD redis.conf /etc/redis/redis.conf
meu@u01:~/docker/dproxy$ cat linkd/Dockerfile 
FROM ubuntu:trusty

RUN apt-get update -y && apt-get dist-upgrade -fy
RUN apt-get install -fy python3 python3-pip
RUN pip3 install docker-py redis
ADD linkd /usr/bin/linkd
RUN chmod +x /usr/bin/linkd
#!/usr/bin/python3

import datetime
import docker
import json
import os
import redis
import sys
import urllib.request


DOCKER_HOST = os.getenv('DOCKER_HOST')
DOCKER_API_BASE_URL = 'tcp://' + DOCKER_HOST
DOCKER_EVENT_API_URL = 'http://' + DOCKER_HOST + '/events'
REDIS_ADDR = os.getenv('REDIS_PORT_6379_TCP_ADDR')
REDIS_PORT = os.getenv('REDIS_PORT_6379_TCP_PORT')

CLIENT = docker.Client(base_url=DOCKER_API_BASE_URL)
EVENT = urllib.request.urlopen(DOCKER_EVENT_API_URL)
REDIS = redis.Redis(host=REDIS_ADDR, port=REDIS_PORT)


def getforwardinfo(container):
    inspect = CLIENT.inspect_container(container.get('Id'))
    env = inspect.get('Config').get('Env')

    name = next(filter(lambda x: 'DPROXY_FORWARD_NAME' in x, env), None)
    if name is None:
        return None
    name = name.split('=').pop()

    ipaddr = inspect.get('NetworkSettings').get('IPAddress')
    port = str(container.get('Ports').pop().get('PrivatePort'))
    forward = ipaddr + ':' + port

    return (name, forward)


def updateredis():
    info = []
    for c in CLIENT.containers():
        tmp = getforwardinfo(c)
        if tmp is None:
            continue
        info.append(tmp)

    REDIS.flushall()
    for name, forward in info:
        REDIS.set(name, forward)


def dumpredis():
    print(datetime.datetime.now().ctime())
    for k in REDIS.scan_iter():
        s = "%10s:\t%s" % (k.decode('utf-8'), REDIS.get(k).decode('utf-8'))
        print(s)


def readevent():
    x = []
    while True:
        c = EVENT.read(1)
        x.append(c)
        if c == b'}':
            break
    return b''.join(x).decode('utf-8')


def main():
    updateredis()
    dumpredis()
    while True:
        ev = readevent()
        status = json.loads(ev).get('status')
        if status in ('start', 'stop'):
            updateredis()
            dumpredis()


if __name__ == '__main__':
    main()
    exit(0)