Docker'da minimal bir flask uygulamasını dağıtma - sunucu bağlantısı sorunları


110

Tek bağımlılığı flask olan, docker dışında iyi çalışan ve varsayılan porta bağlanan bir uygulamam var 5000. İşte tam kaynak:

from flask import Flask

app = Flask(__name__)
app.debug = True

@app.route('/')
def main():
    return 'hi'

if __name__ == '__main__':
    app.run()

Sorun şu ki, bunu docker'da dağıttığımda, sunucu çalışıyor ancak konteynerin dışından ulaşılamıyor.

Aşağıda Dockerfile'ım var. Görüntü, şişesi takılı bir ubuntu. Katran sadece index.pyyukarıda listelenenleri içerir ;

# Dockerfile
FROM dreen/flask
MAINTAINER dreen
WORKDIR /srv

# Get source
RUN mkdir -p /srv
COPY perfektimprezy.tar.gz /srv/perfektimprezy.tar.gz
RUN tar x -f perfektimprezy.tar.gz
RUN rm perfektimprezy.tar.gz

# Run server
EXPOSE 5000
CMD ["python", "index.py"]

İşte dağıtmak için yaptığım adımlar

$> sudo docker build -t perfektimprezy .

Yukarıdakilerin iyi çalıştığını bildiğim kadarıyla, görüntü tar içeriğine sahip /srv. Şimdi sunucuyu bir kapsayıcıda başlatalım:

$> sudo docker run -i -p 5000:5000 -d perfektimprezy
1c50b67d45b1a4feade72276394811c8399b1b95692e0914ee72b103ff54c769

Gerçekten çalışıyor mu?

$> sudo docker ps
CONTAINER ID        IMAGE                   COMMAND             CREATED             STATUS              PORTS                    NAMES
1c50b67d45b1        perfektimprezy:latest   "python index.py"   5 seconds ago       Up 5 seconds        0.0.0.0:5000->5000/tcp   loving_wozniak

$> sudo docker logs 1c50b67d45b1
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with stat

Evet, şişe sunucusu çalışıyor gibi görünüyor. İşin tuhaf olduğu yer burası. Sunucuya bir istekte bulunalım:

 $> curl 127.0.0.1:5000 -v
 * Rebuilt URL to: 127.0.0.1:5000/
 * Hostname was NOT found in DNS cache
 *   Trying 127.0.0.1...
 * Connected to 127.0.0.1 (127.0.0.1) port 5000 (#0)
 > GET / HTTP/1.1
 > User-Agent: curl/7.35.0
 > Host: 127.0.0.1:5000
 > Accept: */*
 >
 * Empty reply from server
 * Connection #0 to host 127.0.0.1 left intact
 curl: (52) Empty reply from server

Boş cevap ... Ama süreç çalışıyor mu?

$> sudo docker top 1c50b67d45b1
UID                 PID                 PPID                C                   STIME               TTY                 TIME                CMD
root                2084                812                 0                   10:26               ?                   00:00:00            python index.py
root                2117                2084                0                   10:26               ?                   00:00:00            /usr/bin/python index.py

Şimdi sunucuya ssh yapalım ve kontrol edelim ...

$> sudo docker exec -it 1c50b67d45b1 bash
root@1c50b67d45b1:/srv# netstat -an
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 127.0.0.1:5000          0.0.0.0:*               LISTEN
tcp        0      0 127.0.0.1:47677         127.0.0.1:5000          TIME_WAIT
Active UNIX domain sockets (servers and established)
Proto RefCnt Flags       Type       State         I-Node   Path
root@1c50b67d45b1:/srv# curl -I 127.0.0.1:5000
HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 5447
Server: Werkzeug/0.10.4 Python/2.7.6
Date: Tue, 19 May 2015 12:18:14 GMT

Sorun değil ... ama dışarıdan değil :( Neyi yanlış yapıyorum?


ilgili şey "<class 'httplib.BadStatusLine'> neden olur", bkz. stackoverflow.com/questions/16592568/…
user2915097

Yine de sadece bir kez bağlanmaya çalışıyorum ve bunun httpie'de bir hata olmadığından oldukça eminim (örneği şimdi curl olarak değiştirdim) veya docker dışında iyi çalıştığı için sunucuda. Bunun bir docker yapılandırma / dağıtım yanlış adım sorunu
olduğuna dair

Konteyneri docker exec -it 1c50b67d45b1 bashve ardından netstat -anbir Flask (kuyruk, kedi ...)
hatalarını ayıklarken

@ user2915097: sunucu içinden bazı çıktılar ekledim
Dreen

'Bağlanamıyorum ...' @Dreen, bağlanabilirsiniz , sadece boş bir yanıt alırsınız ( Connected to 127.0.0.1)
ForceBru

Yanıtlar:


184

Sorun şu ki, yalnızca localhost arayüzüne bağlanıyorsunuz 0.0.0.0, konteynere dışarıdan erişilebilir olmasını istiyorsanız, bağlayıcı olmalısınız . Değiştirirseniz:

if __name__ == '__main__':
    app.run()

-e

if __name__ == '__main__':
    app.run(host='0.0.0.0')

İşe yaramalı.


Bu çözüm işe yarıyor. Bir tam Dockerfile ve piton script kullanarak sonucu görebilirsiniz burada bu çözüm tanımlıyor.

fark ne?
Jwan622

2
@ Jwan622 Localhost arabirimi yalnızca konteynerin içinde kullanılabilir. 0.0.0.0 tüm arabirimlere bağlanır. Arayüzler çeşitli ağlara bağlanır (böylece wifi, lans vb. İçin bir tane olabilir)
Adrian Mouat

5000 numaralı bağlantı noktasını -p 5000:5000, docker runkomutunuzla birlikte bayrakla konteynerinize bağlamayı unutmayın .
T Loch.

40

Kullanırken flaskyerine komutu app.run, sen geçebilir --hostev sahibi değiştirme seçeneği. Docker'daki satır şöyle olacaktır:

CMD ["flask", "run", "--host", "0.0.0.0"]

veya

CMD flask run --host 0.0.0.0

2
Bu çözüm için çok teşekkürler, bende de aynı sorun var, neden app.run(host="0.0.0.0") çalışmamasının sebebi nedir biliyor musunuz ? Ayrıca bu soru için bir gönderi yaptım: stackoverflow.com/q/53133350/3279996
xirururu

1
Bu notta kullanmadığınızdan emin olun python run.py --host=0.0.0.0 . Bu, adlandırma kurallarım nedeniyle ara sıra beni etkiliyor. Bu kod çalışıyor gibi görünecek, ancak sunucu yerel ana bilgisayarda çalışacak.
Braden Holt

1
Bu çalışmaz yerleşik olan şişe sunucusu değil üretim ortamları için geliyordu?
code_dredd

Bu harika, ne sebeple olursa olsun, neredeyse tüm Flask-with-Docker bilgileri Flask CLI'yi kullanamıyor, afaik, bir uygulamayı başlatmak için Flask 1.0 yolu.
Zach Valenta

3
app.run(host="0.0.0.0")Başarısızlık ve CMD ["flask", "run", "--host", "0.0.0.0" ]şampiyon gibi çalışan Flask 1.1.1 ile 2020'de burada .
Joe

2

Docker kapsayıcınızın birden fazla ağ arabirimi vardır. Örneğin, kapsayıcımda şunlar bulunur:

$ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
32: eth0@if33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever

Eğer çalıştırırsanız docker network inspect bridge, yukarıdaki çıktıda konteynerinizin ikinci arayüz ile o köprüye bağlı olduğunu görebilirsiniz. Bu varsayılan köprü, ana makinenizdeki Docker işlemine de bağlıdır.

Bu nedenle şu komutu çalıştırmanız gerekir:

CMD flask run --host 172.17.0.2

Ana makinenizden bir Docker konteynerinde çalışan Flask uygulamanıza erişmek için. 172.17.0.2Konteynırınızın belirli IP adresi neyse onu değiştirin .


2

Öncelikle python betiğinizde kodu değiştirmeniz gerekir.

app.run()

-e

app.run(host="0.0.0.0")

İkinci olarak, docker dosyanızda son satır şöyle olmalıdır:

CMD ["flask", "run", "-h", "0.0.0.0", "-p", "5000"]

Ve üzerinde ana makinede ise 0.0.0.0:5000sizinle denemelisiniz sonra çalışmıyorlocalhost:5000

Not - CMD komutunun doğru olması gerekir. Çünkü CMD komutu, konteynerin yürütülmesi için varsayılanlar sağlar.


2

Diğer cevapların üzerine inşa etmek için:

İki bilgisayarınız olduğunu hayal edin. Her bilgisayarın genel IP'si olan bir ağ arabirimi (örneğin WiFi) vardır. Her bilgisayarın 127.0.0.1'de bir geri döngü / yerel ana bilgisayar arabirimi vardır. Bu, "yalnızca bu bilgisayar" anlamına gelir.

A bilgisayarında 127.0.0.1 listelemişseniz, B bilgisayarında çalışırken 127.0.0.1 aracılığıyla buna bağlanabilmeyi beklemiyorsunuz. Sonuçta, A bilgisayarının yerel , özel adresini dinlemeyi istediniz .

Docker benzer bir kurulumdur; teknik olarak aynı bilgisayar, ancak Linux çekirdeği her bir konteynerin kendi izole ağ yığınıyla çalışmasına izin veriyor. Dolayısıyla, bir kapsayıcıdaki 127.0.0.1, ana bilgisayarınızdan farklı bir bilgisayardaki 127.0.0.1 ile aynıdır - ona bağlanamazsınız.

Şemalarla daha uzun sürüm: https://pythonspeed.com/articles/docker-connection-refused/

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.