วิธีกำหนดค่าการแมปพอร์ต Docker เพื่อใช้ Nginx เป็นพร็อกซีต้นน้ำ


87

อัปเดต II

ตอนนี้วันที่ 16 กรกฎาคม 2015 และสิ่งต่างๆได้เปลี่ยนไปอีกครั้ง ฉันได้ค้นพบคอนเทนเนอร์อัตโนมัตินี้จากJason Wilder : https://github.com/jwilder/nginx-proxyและสามารถแก้ปัญหานี้ได้ตราบเท่าที่ใช้ไปdocker runยังคอนเทนเนอร์ นี่คือวิธีแก้ปัญหาที่ฉันใช้เพื่อแก้ปัญหานี้

อัปเดต

ตอนนี้เป็นเดือนกรกฎาคม 2015 และมีการเปลี่ยนแปลงอย่างมากเกี่ยวกับคอนเทนเนอร์ Docker เครือข่าย ขณะนี้มีข้อเสนอต่างๆมากมายที่ช่วยแก้ปัญหานี้ได้ (หลายวิธี)

คุณควรใช้โพสต์นี้เพื่อทำความเข้าใจพื้นฐานเกี่ยวกับdocker --linkแนวทางในการค้นพบบริการซึ่งเป็นเรื่องพื้นฐานเท่าที่จะทำได้ใช้งานได้ดีและต้องการการเต้นรำแบบแฟนซีน้อยกว่าโซลูชันอื่น ๆ ส่วนใหญ่ มีข้อ จำกัด ว่ามันค่อนข้างยากที่จะสร้างเครือข่ายคอนเทนเนอร์บนโฮสต์ที่แยกจากกันในคลัสเตอร์ใด ๆ ที่กำหนดและไม่สามารถรีสตาร์ทคอนเทนเนอร์ได้เมื่อเชื่อมต่อเครือข่ายแล้ว แต่มีวิธีที่ง่ายและรวดเร็วในการเชื่อมต่อคอนเทนเนอร์เครือข่ายบนโฮสต์เดียวกัน เป็นวิธีที่ดีในการทำความเข้าใจว่าซอฟต์แวร์ที่คุณน่าจะใช้แก้ปัญหานี้กำลังทำอะไรอยู่ภายใต้ประทุน

นอกจากนี้คุณอาจจะต้องการตรวจสอบออกตั้งไข่หางของnetwork, Hashicorp ของconsul, Weaveworks weaveเจฟฟ์ของ Lindsay progrium/consul&gliderlabs/registratorKubernetesและของ Google

นอกจากนี้ยังมีCoreOSการนำเสนอที่ใช้etcd, และfleetflannel

และถ้าคุณอยากจะมีงานเลี้ยงที่คุณสามารถหมุนคลัสเตอร์เพื่อให้ทำงานได้MesosphereหรือหรือDeisFlynn

ถ้าคุณยังใหม่กับการสร้างเครือข่าย (เช่นฉัน) คุณควรหยิบแว่นอ่านหนังสือของคุณเปิด"Paint The Sky With Stars - The Best of Enya"บน Wi-Hi-Fi และดื่มเบียร์ - มันจะเป็น สักพักก่อนที่คุณจะเข้าใจจริงๆว่าคุณกำลังพยายามทำอะไร คำแนะนำ: คุณกำลังพยายามติดตั้งService Discovery LayerในCluster Control Planeไฟล์. เป็นวิธีที่ดีมากในการใช้จ่ายคืนวันเสาร์

มันสนุกมาก แต่ฉันหวังว่าฉันต้องการเวลาที่จะให้ความรู้กับตัวเองดีขึ้นเกี่ยวกับระบบเครือข่ายโดยทั่วไปก่อนที่จะดำน้ำที่เหมาะสมในการฉันในที่สุดพบว่ามีการโพสต์สองสาวจากใจดีเทพดิจิตอลมหาสมุทร Tutorial:. และIntroduction to Networking Terminology Understanding ... Networkingฉันขอแนะนำให้อ่านสองสามครั้งก่อนที่จะดำน้ำ

มีความสุข!



โพสต์ต้นฉบับ

ดูเหมือนว่าฉันจะเข้าใจการแมปพอร์ตสำหรับDockerคอนเทนเนอร์ไม่ได้ วิธีส่งคำขอจาก Nginx ไปยังคอนเทนเนอร์อื่นโดยเฉพาะโดยรับฟังจากพอร์ตอื่นบนเซิร์ฟเวอร์เดียวกัน

ฉันมี Dockerfile สำหรับคอนเทนเนอร์ Nginx ดังนี้:

FROM ubuntu:14.04
MAINTAINER Me <me@myapp.com>

RUN apt-get update && apt-get install -y htop git nginx

ADD sites-enabled/api.myapp.com /etc/nginx/sites-enabled/api.myapp.com
ADD sites-enabled/app.myapp.com /etc/nginx/sites-enabled/app.myapp.com
ADD nginx.conf /etc/nginx/nginx.conf

RUN echo "daemon off;" >> /etc/nginx/nginx.conf

EXPOSE 80 443

CMD ["service", "nginx", "start"]



จากนั้นapi.myapp.comไฟล์กำหนดค่าจะมีลักษณะดังนี้:

upstream api_upstream{

    server 0.0.0.0:3333;

}


server {

    listen 80;
    server_name api.myapp.com;
    return 301 https://api.myapp.com/$request_uri;

}


server {

    listen 443;
    server_name api.mypp.com;

    location / {

        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_cache_bypass $http_upgrade;
        proxy_pass http://api_upstream;

    }

}

แล้วก็อีกapp.myapp.comเช่นกัน

แล้วฉันก็วิ่ง:

sudo docker run -p 80:80 -p 443:443 -d --name Nginx myusername/nginx


และทุกอย่างก็ใช้ได้ดี แต่คำขอไม่ได้รับการส่งผ่านไปยังคอนเทนเนอร์ / พอร์ตอื่น ๆ และเมื่อฉันเข้าสู่คอนเทนเนอร์ Nginx และตรวจสอบบันทึกฉันไม่เห็นข้อผิดพลาด

ความช่วยเหลือใด ๆ


1
กรุณาใส่คำตอบในคำตอบของคุณไม่ใช่ในเนื้อหาของคำถาม
jscs

คำตอบ:


57

คำตอบของ @ T0xicCodeนั้นถูกต้อง แต่ฉันคิดว่าฉันจะขยายรายละเอียดเนื่องจากฉันใช้เวลาประมาณ 20 ชั่วโมงในที่สุดในการแก้ปัญหาที่ใช้งานได้

หากคุณต้องการเรียกใช้ Nginx ในคอนเทนเนอร์ของตัวเองและใช้เป็น reverse proxy เพื่อโหลดแอปพลิเคชันหลายตัวบนอินสแตนซ์เซิร์ฟเวอร์เดียวกันขั้นตอนที่คุณต้องปฏิบัติตามมีดังนี้:

เชื่อมโยงคอนเทนเนอร์ของคุณ

เมื่อคุณใช้docker runคอนเทนเนอร์ของคุณโดยทั่วไปโดยการป้อนเชลล์สคริปต์User Dataคุณสามารถประกาศลิงก์ไปยังคอนเทนเนอร์อื่น ๆ ที่กำลังรันอยู่ ซึ่งหมายความว่าคุณต้องเริ่มคอนเทนเนอร์ตามลำดับและมีเพียงคอนเทนเนอร์หลังเท่านั้นที่สามารถเชื่อมโยงไปยังคอนเทนเนอร์เดิมได้ ชอบมาก:

#!/bin/bash
sudo docker run -p 3000:3000 --name API mydockerhub/api
sudo docker run -p 3001:3001 --link API:API --name App mydockerhub/app
sudo docker run -p 80:80 -p 443:443 --link API:API --link App:App --name Nginx mydockerhub/nginx

ดังนั้นในตัวอย่างนี้APIภาชนะที่ไม่ได้เชื่อมโยงกับคนอื่น ๆ ใด ๆ แต่ Appภาชนะที่มีการเชื่อมโยงAPIและNginxมีการเชื่อมโยงกับทั้งสองและAPIApp

ผลลัพธ์ของสิ่งนี้คือการเปลี่ยนแปลงenvvars และ/etc/hostsไฟล์ที่อยู่ภายในAPIและAppcontainer ผลลัพธ์มีลักษณะดังนี้:

/ etc / hosts

การทำงานcat /etc/hostsภายในNginxคอนเทนเนอร์ของคุณจะให้ผลลัพธ์ดังต่อไปนี้:

172.17.0.5  0fd9a40ab5ec
127.0.0.1   localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.3  App
172.17.0.2  API



ENV Vars

การทำงานenvภายในNginxคอนเทนเนอร์ของคุณจะให้สิ่งต่อไปนี้:

API_PORT=tcp://172.17.0.2:3000
API_PORT_3000_TCP_PROTO=tcp
API_PORT_3000_TCP_PORT=3000
API_PORT_3000_TCP_ADDR=172.17.0.2

APP_PORT=tcp://172.17.0.3:3001
APP_PORT_3001_TCP_PROTO=tcp
APP_PORT_3001_TCP_PORT=3001
APP_PORT_3001_TCP_ADDR=172.17.0.3

ฉันได้ตัด vars จริงหลายรายการออกไปแล้ว แต่ข้างต้นเป็นค่าหลักที่คุณต้องใช้ในการรับส่งข้อมูลพร็อกซีไปยังคอนเทนเนอร์ของคุณ

ในการรับเชลล์เพื่อรันคำสั่งข้างต้นภายในคอนเทนเนอร์ที่กำลังรันอยู่ให้ใช้สิ่งต่อไปนี้:

sudo docker exec -i -t Nginx bash

คุณจะเห็นว่าตอนนี้คุณมีทั้ง/etc/hostsรายการไฟล์และenvตัวแปรที่มีที่อยู่ IP ในเครื่องสำหรับคอนเทนเนอร์ใด ๆ ที่เชื่อมโยง เท่าที่ฉันบอกได้นี่คือทั้งหมดที่เกิดขึ้นเมื่อคุณเรียกใช้คอนเทนเนอร์ที่มีการประกาศตัวเลือกลิงก์ แต่ตอนนี้คุณสามารถใช้ข้อมูลนี้เพื่อกำหนดค่าnginxภายในNginxคอนเทนเนอร์ของคุณได้



การกำหนดค่า Nginx

นี่คือสิ่งที่ยุ่งยากเล็กน้อยและมีสองตัวเลือก คุณสามารถเลือกที่จะกำหนดค่าไซต์ของคุณให้ชี้ไปที่รายการใน/etc/hostsไฟล์ที่dockerสร้างขึ้นหรือคุณสามารถใช้ENVvars และเรียกใช้การแทนที่สตริง (ฉันใช้sed) ในnginx.confไฟล์ conf อื่น ๆของคุณและอื่น ๆ ที่อาจอยู่ใน/etc/nginx/sites-enabledโฟลเดอร์ของคุณเพื่อแทรก IP ค่า



ตัวเลือก A: กำหนดค่า Nginx โดยใช้ ENV Vars

นี่เป็นตัวเลือกที่ฉันใช้เพราะฉันไม่สามารถรับ /etc/hostsตัวเลือกไฟล์ให้ทำงานได้ ฉันจะลองใช้ตัวเลือก B เร็วพอและอัปเดตโพสต์นี้พร้อมสิ่งที่ค้นพบ

ความแตกต่างที่สำคัญระหว่างอ็อพชันนี้และการใช้/etc/hostsอ็อพชันไฟล์คือวิธีที่คุณเขียนDockerfileเพื่อใช้เชลล์สคริปต์เป็นCMDอาร์กิวเมนต์ซึ่งจะจัดการกับการแทนที่สตริงเพื่อคัดลอกค่า IP จากENVไปยังไฟล์ conf ของคุณ

นี่คือชุดไฟล์การกำหนดค่าที่ฉันลงเอยด้วย:

Dockerfile

FROM ubuntu:14.04
MAINTAINER Your Name <you@myapp.com>

RUN apt-get update && apt-get install -y nano htop git nginx

ADD nginx.conf /etc/nginx/nginx.conf
ADD api.myapp.conf /etc/nginx/sites-enabled/api.myapp.conf
ADD app.myapp.conf /etc/nginx/sites-enabled/app.myapp.conf
ADD Nginx-Startup.sh /etc/nginx/Nginx-Startup.sh

EXPOSE 80 443

CMD ["/bin/bash","/etc/nginx/Nginx-Startup.sh"]

nginx.conf

daemon off;
user www-data;
pid /var/run/nginx.pid;
worker_processes 1;


events {
    worker_connections 1024;
}


http {

    # Basic Settings

    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 33;
    types_hash_max_size 2048;

    server_tokens off;
    server_names_hash_bucket_size 64;

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


    # Logging Settings
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;


    # Gzip Settings

gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 3;
    gzip_buffers 16 8k;
    gzip_http_version 1.1;
    gzip_types text/plain text/xml text/css application/x-javascript application/json;
    gzip_disable "MSIE [1-6]\.(?!.*SV1)";

    # Virtual Host Configs  
    include /etc/nginx/sites-enabled/*;

    # Error Page Config
    #error_page 403 404 500 502 /srv/Splash;


}

หมายเหตุ: สิ่งสำคัญคือต้องรวมdaemon off;ไว้ในnginx.confไฟล์ของคุณเพื่อให้แน่ใจว่าคอนเทนเนอร์ของคุณจะไม่ออกทันทีหลังจากเปิดตัว

api.myapp.conf

upstream api_upstream{
    server APP_IP:3000;
}

server {
    listen 80;
    server_name api.myapp.com;
    return 301 https://api.myapp.com/$request_uri;
}

server {
    listen 443;
    server_name api.myapp.com;

    location / {
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_cache_bypass $http_upgrade;
        proxy_pass http://api_upstream;
    }

}

Nginx-Startup.sh

#!/bin/bash
sed -i 's/APP_IP/'"$API_PORT_3000_TCP_ADDR"'/g' /etc/nginx/sites-enabled/api.myapp.com
sed -i 's/APP_IP/'"$APP_PORT_3001_TCP_ADDR"'/g' /etc/nginx/sites-enabled/app.myapp.com

service nginx start

ฉันจะปล่อยให้มันขึ้นอยู่กับคุณที่จะทำบ้านของคุณเกี่ยวกับที่สุดของเนื้อหาของและnginx.confapi.myapp.conf

ความมหัศจรรย์เกิดขึ้นในNginx-Startup.shที่ที่เราใช้sedในการแทนที่สตริงบนAPP_IPตัวยึดตำแหน่งที่เราเขียนไว้ในupstreamบล็อกของเราapi.myapp.confและapp.myapp.confไฟล์

คำถาม ask.ubuntu.com นี้อธิบายได้ดีมาก: ค้นหาและแทนที่ข้อความภายในไฟล์โดยใช้คำสั่ง

GOTCHA บน OSX sedจัดการตัวเลือกต่างกัน-iโดยเฉพาะแฟล็ก บน Ubuntu -iธงจะจัดการแทนที่ 'ในสถานที่'; มันจะเปิดไฟล์เปลี่ยนข้อความแล้ว 'บันทึกทับ' ไฟล์เดียวกัน บน OSX -iแฟล็กต้องการนามสกุลไฟล์ที่คุณต้องการให้ไฟล์ผลลัพธ์มี หากคุณกำลังทำงานกับไฟล์ที่ไม่มีนามสกุลคุณต้องป้อน '' เป็นค่าสำหรับ-iแฟล็ก

GOTCHA ในการใช้ตัวแปร ENV ภายใน regex ที่sedใช้ค้นหาสตริงที่คุณต้องการแทนที่คุณต้องตัด var ภายในเครื่องหมายคำพูดคู่ ดังนั้นไวยากรณ์ที่ถูกต้องแม้ว่าจะดูว่องไว แต่ก็เป็นไปตามด้านบน

ดังนั้นนักเทียบท่าจึงได้เปิดใช้งานคอนเทนเนอร์ของเราและทริกเกอร์Nginx-Startup.shสคริปต์ให้ทำงานซึ่งใช้sedเพื่อเปลี่ยนค่าAPP_IPเป็นENVตัวแปรที่เกี่ยวข้องที่เราระบุไว้ในsedคำสั่ง ตอนนี้เรามีไฟล์ conf ภายใน/etc/nginx/sites-enabledไดเร็กทอรีของเราซึ่งมีที่อยู่ IP จากENVvars ที่ docker ตั้งไว้เมื่อเริ่มต้นคอนเทนเนอร์ ภายในapi.myapp.confไฟล์ของคุณคุณจะเห็นupstreamบล็อกเปลี่ยนเป็น:

upstream api_upstream{
    server 172.0.0.2:3000;
}

ที่อยู่ IP ที่คุณเห็นอาจแตกต่างกัน แต่ฉันสังเกตเห็นว่าโดยปกติ172.0.0.xแล้ว

ตอนนี้คุณควรมีการกำหนดเส้นทางทุกอย่างอย่างเหมาะสม

GOTCHA คุณไม่สามารถรีสตาร์ท / รันคอนเทนเนอร์ใหม่ได้เมื่อคุณรันการเรียกใช้อินสแตนซ์เริ่มต้น Docker จัดเตรียม IP ใหม่ให้แต่ละคอนเทนเนอร์เมื่อเปิดตัวและดูเหมือนจะไม่มีการนำสิ่งที่เคยใช้มาก่อน ดังนั้นapi.myapp.comจะได้ 172.0.0.2 ในครั้งแรก แต่จะได้ 172.0.0.4 ในครั้งต่อไป แต่Nginxจะตั้งค่า IP แรกลงในไฟล์ conf หรือใน/etc/hostsไฟล์แล้วดังนั้นจึงไม่สามารถกำหนด IP ใหม่สำหรับapi.myapp.com. วิธีแก้ปัญหานี้มีแนวโน้มที่จะใช้CoreOSและetcdบริการซึ่งในความเข้าใจที่ จำกัด ของฉันทำหน้าที่เหมือนแชร์ENVสำหรับทุกเครื่องที่ลงทะเบียนในCoreOSคลัสเตอร์เดียวกัน นี่คือของเล่นชิ้นต่อไปที่ฉันจะเล่นกับการตั้งค่า



ตัวเลือก B: ใช้/etc/hostsรายการไฟล์

นี่ควรเป็นวิธีที่เร็วกว่าและง่ายกว่าในการทำ แต่ฉันไม่สามารถใช้งานได้ คุณแค่ใส่ค่าของ/etc/hostsรายการapi.myapp.confและapp.myapp.confไฟล์ของคุณอย่างชัดเจนแต่ฉันไม่สามารถใช้วิธีนี้ได้

UPDATE: ดูคำตอบของ @Wes Todสำหรับคำแนะนำในการทำให้วิธีนี้ได้ผล

นี่คือความพยายามที่ฉันทำในapi.myapp.conf:

upstream api_upstream{
    server API:3000;
}

เมื่อพิจารณาว่ามีรายการใน/etc/hostsไฟล์ของฉันเป็นดังนี้: 172.0.0.2 APIฉันคิดว่ามันจะดึงค่าเข้ามา แต่ดูเหมือนจะไม่เป็นเช่นนั้น

ฉันยังมีปัญหาเสริมอีกสองสามประการเกี่ยวกับการElastic Load Balancerจัดหาจาก AZ ทั้งหมดซึ่งอาจเป็นปัญหาเมื่อฉันลองใช้เส้นทางนี้ แต่ฉันต้องเรียนรู้วิธีจัดการการเปลี่ยนสตริงใน Linux ดังนั้นมันจึงเป็นเรื่องสนุก เดี๋ยวจะลองดูว่าจะเป็นยังไง


2
gotcha อีกอันที่ใช้ลิงค์คือถ้าคุณรีสตาร์ทคอนเทนเนอร์ API ก็มักจะได้รับ ip ใหม่ สิ่งนี้ไม่ได้แสดงในไฟล์ nginx container / etc / hosts ซึ่งจะยังคงใช้ ip เก่าต่อไปดังนั้นจึงต้องรีสตาร์ทด้วย
judoole

13

ฉันลองใช้พร็อกซีย้อนกลับ Jason Wilder ยอดนิยมที่ใช้รหัสได้อย่างน่าอัศจรรย์สำหรับทุกคนและเรียนรู้ว่ามันไม่ได้ผลสำหรับทุกคน (เช่นฉัน) และฉันยังใหม่กับ NGINX และไม่ชอบที่ฉันไม่เข้าใจเทคโนโลยีที่ฉันพยายามใช้

ต้องการเพิ่ม 2 เซ็นต์ของฉันเนื่องจากการสนทนาข้างต้นเกี่ยวกับlinkingคอนเทนเนอร์ที่อยู่ร่วมกันได้ลงวันที่แล้วเนื่องจากเป็นคุณลักษณะที่เลิกใช้แล้ว networksดังนั้นนี่คือคำอธิบายเกี่ยวกับวิธีการทำโดยใช้ คำตอบนี้เป็นตัวอย่างทั้งหมดของการตั้งค่า nginx เป็น reverse proxy ไปยังเว็บไซต์ที่มีเพจแบบคงที่โดยใช้Docker Composeและการกำหนดค่า nginx

TL; DR;

เพิ่มบริการที่ต้องพูดคุยกันบนเครือข่ายที่กำหนดไว้ล่วงหน้า สำหรับการสนทนาทีละขั้นตอนเกี่ยวกับเครือข่าย Docker ฉันได้เรียนรู้บางสิ่งที่นี่: https://technologyconversations.com/2016/04/25/docker-networking-and-dns-the-good-the-bad-and- น่าเกลียด/

กำหนดเครือข่าย

ก่อนอื่นเราต้องมีเครือข่ายที่บริการแบ็กเอนด์ทั้งหมดของคุณสามารถพูดคุยได้ ฉันเรียกว่าของฉันwebแต่มันสามารถเป็นอะไรก็ได้ที่คุณต้องการ

docker network create web

สร้างแอป

เราจะทำแอพเว็บไซต์ง่ายๆ เว็บไซต์นี้เป็นหน้า index.html ธรรมดาที่ให้บริการโดยคอนเทนเนอร์ nginx เนื้อหาเป็นไดรฟ์ข้อมูลที่ต่อกับโฮสต์ภายใต้โฟลเดอร์content

DockerFile:

FROM nginx
COPY default.conf /etc/nginx/conf.d/default.conf

default.conf

server {
    listen       80;
    server_name  localhost;

    location / {
        root   /var/www/html;
        index  index.html index.htm;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

docker-compose.yml

version: "2"

networks:
  mynetwork:
    external:
      name: web

services:
  nginx:
    container_name: sample-site
    build: .
    expose:
      - "80"
    volumes:
      - "./content/:/var/www/html/"
    networks:
      default: {}
      mynetwork:
        aliases:
          - sample-site

โปรดทราบว่าเราไม่ต้องการการแมปพอร์ตที่นี่อีกต่อไป เราเปิดเผยพอร์ต 80 ง่ายๆนี่เป็นประโยชน์สำหรับการหลีกเลี่ยงการชนกันของพอร์ต

เรียกใช้แอพ

เปิดเว็บไซต์นี้ด้วย

docker-compose up -d

การตรวจสอบสนุก ๆ เกี่ยวกับการแมป DNS สำหรับคอนเทนเนอร์ของคุณ:

docker exec -it sample-site bash
ping sample-site

ping นี้ควรใช้งานได้ภายในคอนเทนเนอร์ของคุณ

สร้าง Proxy

Nginx Reverse Proxy:

Dockerfile

FROM nginx

RUN rm /etc/nginx/conf.d/*

เรารีเซ็ตการกำหนดค่าโฮสต์เสมือนทั้งหมดเนื่องจากเราจะปรับแต่ง

docker-compose.yml

version: "2"

networks:
  mynetwork:
    external:
      name: web


services:
  nginx:
    container_name: nginx-proxy
    build: .
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./conf.d/:/etc/nginx/conf.d/:ro
      - ./sites/:/var/www/
    networks:
      default: {}
      mynetwork:
        aliases:
          - nginx-proxy

เรียกใช้ Proxy

เปิดพร็อกซีโดยใช้ความไว้วางใจของเรา

docker-compose up -d

สมมติว่าไม่มีปัญหาแสดงว่าคุณมีคอนเทนเนอร์สองตู้ที่ทำงานอยู่ซึ่งสามารถพูดคุยกันได้โดยใช้ชื่อของพวกเขา มาทดสอบกันเลย

docker exec -it nginx-proxy bash
ping sample-site
ping nginx-proxy

ตั้งค่าโฮสต์เสมือน

รายละเอียดสุดท้ายคือการตั้งค่าไฟล์โฮสติ้งเสมือนเพื่อให้พร็อกซีสามารถกำหนดทิศทางการรับส่งข้อมูลตามที่คุณต้องการตั้งค่าการจับคู่ของคุณ:

ตัวอย่าง site.conf สำหรับการกำหนดค่าโฮสติ้งเสมือนของเรา:

  server {
    listen 80;
    listen [::]:80;

    server_name my.domain.com;

    location / {
      proxy_pass http://sample-site;
    }

  }

ขึ้นอยู่กับวิธีการตั้งค่าพร็อกซีคุณจะต้องเก็บไฟล์นี้ไว้ในconf.dโฟลเดอร์ในเครื่องของคุณซึ่งเราติดตั้งผ่านการvolumesประกาศในdocker-composeไฟล์

สุดท้าย แต่ไม่ท้ายสุดบอกให้ nginx โหลดการกำหนดค่าอีกครั้ง

docker exec nginx-proxy service nginx reload

ลำดับขั้นตอนเหล่านี้เป็นจุดสุดยอดของชั่วโมงแห่งความปวดเมื่อยหัวในขณะที่ฉันต่อสู้กับข้อผิดพลาด 502 Bad Gateway ที่เจ็บปวดและเรียนรู้ nginx เป็นครั้งแรกเนื่องจากประสบการณ์ส่วนใหญ่ของฉันอยู่กับ Apache

คำตอบนี้คือการสาธิตวิธีการฆ่าข้อผิดพลาด 502 Bad Gateway ที่เป็นผลมาจากการที่คอนเทนเนอร์ไม่สามารถพูดคุยกันได้

ฉันหวังว่าคำตอบนี้จะช่วยใครบางคนออกไปได้หลายชั่วโมงแห่งความเจ็บปวดเนื่องจากการได้รับตู้คอนเทนเนอร์เพื่อคุยกันนั้นยากที่จะเข้าใจด้วยเหตุผลบางประการแม้ว่าจะเป็นสิ่งที่ฉันคาดว่าจะเป็นกรณีการใช้งานที่ชัดเจนก็ตาม แต่แล้วอีกครั้งฉันโง่ และโปรดแจ้งให้เราทราบว่าฉันจะปรับปรุงแนวทางนี้ได้อย่างไร


อา! โอเล่502 Gateway Errorคลาสสิกที่น่าอับอายในทุกวันนี้ ขอบคุณ @gdbj ที่ช่วยเพิ่มเวลาในการสนทนาและให้คำตอบโดยละเอียด
AJB

แค่อยากจะบอกว่าขอบคุณที่สละเวลานี้มันช่วยให้ฉันไม่ยุ่งยาก ขอขอบคุณ.
Single Entity

10

การใช้ลิงก์นักเทียบท่าคุณสามารถเชื่อมโยงคอนเทนเนอร์ต้นน้ำกับคอนเทนเนอร์ nginx คุณลักษณะเพิ่มเติมคือนักเทียบท่าจัดการไฟล์โฮสต์ซึ่งหมายความว่าคุณจะสามารถอ้างถึงคอนเทนเนอร์ที่เชื่อมโยงโดยใช้ชื่อแทนที่จะเป็น ip แบบสุ่ม


7

"ตัวเลือก B" ของ AJBสามารถทำให้ทำงานได้โดยใช้อิมเมจพื้นฐานของ Ubuntu และตั้งค่า nginx ด้วยตัวคุณเอง (มันใช้ไม่ได้เมื่อฉันใช้อิมเมจ Nginx จาก Docker Hub)

นี่คือไฟล์ Docker ที่ฉันใช้:

FROM ubuntu
RUN apt-get update && apt-get install -y nginx
RUN ln -sf /dev/stdout /var/log/nginx/access.log
RUN ln -sf /dev/stderr /var/log/nginx/error.log
RUN rm -rf /etc/nginx/sites-enabled/default
EXPOSE 80 443
COPY conf/mysite.com /etc/nginx/sites-enabled/mysite.com
CMD ["nginx", "-g", "daemon off;"]

การกำหนดค่า nginx ของฉัน (aka: conf / mysite.com):

server {
    listen 80 default;
    server_name mysite.com;

    location / {
        proxy_pass http://website;
    }
}

upstream website {
    server website:3000;
}

และสุดท้ายฉันจะเริ่มตู้คอนเทนเนอร์ได้อย่างไร:

$ docker run -dP --name website website
$ docker run -dP --name nginx --link website:website nginx

สิ่งนี้ทำให้ฉันเริ่มทำงานได้ดังนั้น nginx ของฉันจึงชี้ต้นน้ำไปยังคอนเทนเนอร์นักเทียบท่าที่สองซึ่งเปิดพอร์ต 3000


ขอบคุณสำหรับความช่วยเหลือ Wes! ฉันจะลองดูเมื่อฉันกลับมาจากวันหยุดพักผ่อน
AJB

ฉันมีปัญหาบางอย่างเช่นนี้กับภาพทางการ ฉันพบว่ามันดีกว่ามากที่จะตั้งฐานออกจากกล่องอูบุนตูแล้วดึงเส้นจากไฟล์นักเทียบท่าโดยตรง ไม่ใช่ว่าสิ่งนี้ควรจำเป็น แต่อนิจจา ....
Wes Todd

1
สิ่งนี้ยอดเยี่ยม แต่สิ่งที่ฉันไม่ได้รับคือการกำหนดค่า nginx เพียงแค่รู้ค่าของ 'เว็บไซต์' Nginx magic หรือ docker magic หรืออย่างอื่น?
Kyle Chadha

1
บรรทัดupstream website {กำหนดมูลค่าเว็บไซต์สำหรับ nginx นั่นคือสิ่งที่คุณใช้ในproxy_passไฟล์. ส่วนนักเทียบท่าของสิ่งนี้ใช้ชื่อเดียวกันเพื่อความสอดคล้อง แต่ไม่เกี่ยวข้องกับการตั้งค่า nginx เพื่อให้ชัดเจนขึ้นเล็กน้อยควรอ่านพร็อกซี:upstream website { server localhost:3000; }
Wes Todd

2
ฉันใช้ภาพ nginx อย่างเป็นทางการล่าสุด (1.9.2) และดูเหมือนว่าจะใช้งานได้ดี บางทีพวกเขาอาจแก้ไขปัญหาได้
Pejvan

6

คำตอบของ @ gdbj เป็นคำอธิบายที่ดีและเป็นคำตอบที่ทันสมัยที่สุด อย่างไรก็ตามนี่เป็นวิธีที่ง่ายกว่า

ดังนั้นหากคุณต้องการเปลี่ยนเส้นทางการรับส่งข้อมูลทั้งหมดจาก nginx ไป80ยังการเปิดเผยคอนเทนเนอร์อื่นการ8080กำหนดค่าขั้นต่ำอาจเป็นเพียง:

nginx.conf:

server {
    listen 80;

    location / {
        proxy_pass http://client:8080; # this one here
        proxy_redirect off;
    }

}

docker-compose.yml

version: "2"
services:
  entrypoint:
    image: some-image-with-nginx
    ports:
      - "80:80"
    links:
      - client  # will use this one here

  client:
    image: some-image-with-api
    ports:
      - "8080:8080"

เอกสาร Docker


ตอนแรกฉันคิดว่าคุณจะมีปัญหากับพอร์ตชนกัน
gdbj

@gdbj ปัญหาของฉันคือความละเอียด url / ip ระหว่างคอนเทนเนอร์ เดาว่าเรามีเหมือนกัน ในกรณีของคุณคุณใช้เครือข่ายซึ่งก็ใช้งานได้ดีเช่นกันในกรณีของฉันฉันเพียงแค่เชื่อมโยงคอนเทนเนอร์
Diolor

เยี่ยมมากนั่นคือทั้งหมดที่ฉันต้องการ! ขอบคุณสำหรับคำตอบนั้น
Floran Gmehlin

2

เพิ่งพบบทความจาก Anand Mani Sankar ซึ่งแสดงวิธีง่ายๆในการใช้ nginx upstream proxy กับนักแต่งเพลงนักเทียบท่า

โดยพื้นฐานแล้วเราต้องกำหนดค่าการเชื่อมโยงอินสแตนซ์และพอร์ตที่ไฟล์ docker-compose และอัปเดตอัปสตรีมที่ nginx.conf ตามนั้น


1
บทความนี้ใช้linksซึ่งเลิกใช้แล้ว ใช้เครือข่ายเลย: docs.docker.com/engine/userguide/networking
gdbj

การทดแทน nginx ที่มีมนต์ขลังจะทำงานในกรณีนี้ด้วยหรือไม่?
Dormouse
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.