Dieser Artikel ist der 11. Tag von Recruit Lifestyle Adventskalender 2015 - Qiita. Ich bin moremagisch und für die Entwicklung bei Hot Pepper Beauty verantwortlich. Wir arbeiten im App-Infrastruktur-Team, um Entwicklern zu helfen.
Benutzt ihr Docker? Ich habe vor kurzem angefangen, es zu benutzen, aber es ist wahnsinnig praktisch!
Mit zunehmender Anzahl von Containern ist es jedoch schwierig, sich die Portnummer zu merken. .. Es ist auch fantastisch, dass Sie nur anhand der Portnummer wissen können, auf welchen Dienst Sie zugreifen. Anstatt den Container auf den Zugriff nach Portnummer umzustellen Wäre es nicht einfacher zu verstehen, wenn der Containername den Domainnamen so wie er ist eingegeben hätte?
Dieses Mal werde ich über den Zugriff mit Docker mit dem Containernamen als Subdomain sprechen.
Zum Beispiel ,,
Der Name des Servers, auf dem Docker ausgeführt wird, lautet "example.com"
Containername dev-tomcat
Angenommen, Port 8080 leitet an Port 49000 weiter
Normalerweise, wenn Sie auf Port 8080 des oben genannten dev-tomcat-Containers zugreifen möchten Weil Port 8080 an Port 49000 weiterleitet Zugriff wie folgt.
http://example.com:49000/
Wenn nur ein Container gestartet wird, ist dies nicht schwierig. Es ist schwer zu merken, wann die Anzahl der Container und Services zunimmt. Wenn Sie einen Fehler machen, stellen Sie eine Verbindung zu einem anderen Dienst her.
So ist es für Menschen leicht zu verstehen
http://dev-tomcat-8080.example.com
Es ist eine Geschichte, um es wie oben beschrieben zugänglich zu machen. In diesem Fall können Sie darauf zugreifen, indem Sie sich den Containernamen und den Port merken, der tatsächlich im Container ausgeführt wird!
Erstellen Sie einen Container mit Namensauflösung und starten Sie ihn, damit auf die Subdomäne für den Containernamen auf dem Server zugegriffen werden kann. Da dies über den http-Proxy realisiert wird, ist die Auflösung von Subdomains nur für das http-Protokoll möglich.
Die Containerinformationen von Docker werden regelmäßig im Container gespeichert, indem der Container mit Namensauflösung gestartet wird. Sie können über den Containernamen zugreifen, ohne die Einstellungsdatei bei jedem Start des Containers neu zu schreiben.
Es gibt eine Docker-Umgebung, und der Host, auf dem Docker ausgeführt wird, kann den Namen auflösen. Docker's RemoteAPI aktiviert
Bereiten Sie die folgenden Dateien vor und erstellen Sie ein Docker-Image Legen Sie eine andere Datei als Dockerfile in einem geeigneten Ordner gemäß der Beschreibung von Dockerfile ab.
Das Dockerfile sieht so aus. Installieren Sie redis, python3, nginx basierend auf ubuntu: 14.04 Ich mache eine Start-Shell und drücke sie beim Start
Dockerfile
FROM ubuntu:14.04
~ Ausgelassen ~
# python3 install
RUN apt-get install -y python3 python3-pip && apt-get clean
RUN pip3 install redis
ADD redis/regist.py /usr/sbin/regist.py
RUN chmod +x /usr/sbin/regist.py
# redis
RUN apt-get update && apt-get install -fy redis-server
ADD redis/redis.conf /etc/redis/redis.conf
# nginx install
RUN apt-get -y install nginx lua-nginx-redis && apt-get clean
ADD nginx/default /etc/nginx/sites-available/
ADD nginx/rewrite.lua /etc/nginx/sites-available/
ADD nginx/cert/ /etc/nginx/cert/
#Start-Shell erstellen
RUN printf '#!/bin/bash \n\
/usr/bin/redis-server & \n\
/usr/sbin/regist.py > /dev/null & \n\
/etc/init.d/nginx start \n\
/etc/init.d/nginx reload \n\
/usr/sbin/sshd -D \n\
tail -f /var/null \n\
' >> /etc/service.sh \
&& chmod +x /etc/service.sh
EXPOSE 22 6379 80 443
CMD /etc/service.sh
nginx Der Schlüssel zum Vorgang, die Nginx-Konfigurationsdatei, sieht folgendermaßen aus. Der Server wartet auf 80.443 und ist auf Umschreiben → Prozess eingestellt.
default
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
root /usr/share/nginx/html;
index index.html index.htm;
server_name localhost;
location / {
set $upstream "";
rewrite_by_lua_file /etc/nginx/sites-available/rewrite.lua;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://$upstream;
client_max_body_size 200M;
}
}
server {
listen 443;
server_name localhost;
ssl on;
ssl_certificate /etc/nginx/cert/ssl.crt;
ssl_certificate_key /etc/nginx/cert/ssl.key;
ssl_session_timeout 5m;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
location / {
set $upstream "";
rewrite_by_lua_file /etc/nginx/sites-available/rewrite.lua;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass https://$upstream;
client_max_body_size 200M;
}
}
rewrite.lua Rufen Sie den Containernamen und die Portnummer vom Hostnamen ab. Wenden Sie sich an redis und geben Sie den eigentlichen Behälter zurück
rewrite.lua
local routes = _G.routes
if routes == nil then
routes = {}
ngx.log(ngx.ALERT, "[[[Route cache is empty.]]")
end
local container_name = string.sub(ngx.var.http_host, 1, string.find(ngx.var.http_host, "%.")-1)
local route = routes[container_name]
if route == nil then
local Redis = require "nginx.redis"
local client = Redis:new()
client:set_timeout(1000)
local ok, err = client:connect("127.0.0.1", 6379)
if not ok then
ngx.log(ngx.ERR, "************ Redis connection failure: " .. err)
return
end
route = client:get(container_name)
end
ngx.log(ngx.ALERT, route)
-- fallback to redis for lookups
if route ~= nil then
ngx.var.upstream = route
routes[container_name] = route
else
ngx.log(ngx.ALERT, "=ng=[[[route null]]]")
ngx.exit(ngx.HTTP_NOT_FOUND)
end
python Es ist ein Spieler hinter den Kulissen, der Containerinformationen in Redis speichert. Die Containerinformationen werden alle 3 Sekunden über die Remote-API von Docker aktualisiert. Ich habe es die ganze Zeit in einer Schleife ausgeführt, aber es kann noch ein bisschen mehr geben. .. ..
regist.py
#!/usr/bin/python3
import os
import sys
import time
import json
import redis
import urllib.request
DOCKER_HOST = os.getenv('DOCKER_HOST')
REDIS_ADDR = '127.0.0.1'
REDIS_PORT = 6379
def redisDump():
conn = redis.Redis(host=REDIS_ADDR, port=REDIS_PORT)
for key in conn.keys():
print(key)
print(conn.get(key))
return conn.keys()
def addData(datas):
conn = redis.Redis(host=REDIS_ADDR, port=REDIS_PORT)
for key in set(list(datas.keys()) + list(conn.keys())):
if isinstance(key, bytes):
key = key.decode('utf-8')
if key in datas:
conn.set(key, datas[key])
else:
conn.delete(key)
def getContainers():
response = urllib.request.urlopen('http://' + DOCKER_HOST + '/containers/json?all=1')
jsonData = json.loads(response.read().decode('utf-8'))
datas = {}
for con in jsonData:
name = con['Names'][-1][1:]
con_ip = getIpAddress(con['Id'])
for port in con['Ports']:
key = name + '-' + str(port['PrivatePort'])
value=con_ip + ':' + str(port['PrivatePort'])
datas[key] = value
return datas
def getIpAddress(con_id):
response = urllib.request.urlopen('http://' + DOCKER_HOST + '/containers/' + con_id + '/json')
jsonData = json.loads(response.read().decode('utf-8'))
#print(json.dumps(jsonData))
ret = jsonData['NetworkSettings']['IPAddress']
return ret
while True:
addData(getContainers())
print( redisDump() )
sys.stdout.flush()
time.sleep(3)
Gehen Sie zu dem Ordner, in dem die Docker-Datei gespeichert ist, und geben Sie den folgenden Befehl ein!
# docker build -t docker-discovery .
Starten Sie das zuvor erstellte Image. Da die Containerinformationen mithilfe der DockerRemote-API von Docker erfasst werden, die auf dem Host im Container ausgeführt wird, werde ich sie beim Start buchstabieren.
# docker run -d -p 80:80 -p 443: 443 -e DOCKER_HOST = <IP-Adresse des Docker-Hosts>: <RemoteAPI-Port> --name Docker-Discovery Docker-Discovery
Dies ist alles, was Sie zur Namensauflösung benötigen!
Angenommen, der Host, auf dem Docker ausgeführt wird, ist example.com Sie können mit der folgenden URL eine Verbindung zum entsprechenden Container herstellen.
http: // {Containername} - {Portnummer im öffentlichen Container} .example.com
Beginnen wir den TeamCity-Container als Testversion.
docker run -dP --name teamcity moremagic/teamcity
Dieser Container stellt Port 8111 der Außenwelt zur Verfügung, sodass Sie unter der folgenden URL darauf zugreifen können. http://teamcity-8111.example.com
Viel Spaß mit Docker!
Recommended Posts