Menerapkan aplikasi flask minimal di buruh pelabuhan - masalah koneksi server

108

Saya memiliki aplikasi yang hanya ketergantungannya adalah flask, yang bekerja dengan baik di luar buruh pelabuhan dan mengikat ke port default 5000. Berikut sumber lengkapnya:

from flask import Flask

app = Flask(__name__)
app.debug = True

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

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

Masalahnya adalah ketika saya menerapkan ini di buruh pelabuhan, server sedang berjalan tetapi tidak dapat dijangkau dari luar penampung.

Di bawah ini adalah Dockerfile saya. Gambar tersebut adalah ubuntu dengan flask terpasang. Tar hanya berisi yang index.pytercantum di atas;

# 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"]

Berikut langkah-langkah yang saya lakukan untuk menerapkan

$> sudo docker build -t perfektimprezy .

Sejauh yang saya tahu di atas berjalan dengan baik, gambar memiliki isi tar /srv. Sekarang, mari kita mulai server dalam sebuah wadah:

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

Apakah itu benar-benar berjalan?

$> 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

Ya, sepertinya server flask sedang berjalan. Di sinilah menjadi aneh. Mari kita membuat permintaan ke server:

 $> 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

Balasan kosong ... Tetapi apakah prosesnya berjalan?

$> 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

Sekarang mari ssh ke server dan periksa ...

$> 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

Tidak apa-apa ... tapi tidak dari luar :( Apa salahku?

Dreen
sumber
hal yang relevan adalah "Disebabkan oleh <class 'httplib.BadStatusLine'>", lihat stackoverflow.com/questions/16592568/…
user2915097
Saya hanya mencoba untuk menghubungkan sekali dan saya cukup yakin ini bukan bug di httpie (saya mengubah contoh menjadi curl sekarang), atau di server karena berfungsi dengan baik di luar buruh pelabuhan. Saya merasa kuat ini adalah masalah kesalahan langkah konfigurasi / penerapan buruh pelabuhan
Dreen
Periksa containernya dengan docker exec -it 1c50b67d45b1 bashperintah biasa netstat -anatau perintah apa pun yang akan Anda lakukan saat men-debug Flask (tail, cat ...)
user2915097
@ user2915097: ive menambahkan beberapa output dari dalam server
Dreen
'Tidak dapat terhubung ...' @Dreen, Anda dapat terhubung , Anda hanya mendapatkan balasan kosong ( Connected to 127.0.0.1)
ForceBru

Jawaban:

179

Masalahnya adalah Anda hanya mengikat antarmuka localhost, Anda harus mengikat 0.0.0.0jika Anda ingin wadah dapat diakses dari luar. Jika Anda berubah:

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

untuk

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

Ini harus berhasil.

Adrian Mouat
sumber
Solusi ini berhasil. Seseorang dapat melihat hasilnya menggunakan skrip Dockerfile dan python lengkap di sini seperti yang dijelaskan oleh solusi ini.
apa bedanya?
Jwan622
1
@ Jwan622 Antarmuka localhost hanya tersedia di dalam wadah. 0.0.0.0 mengikat semua antarmuka. Antarmuka terhubung ke berbagai jaringan (sehingga Anda dapat memilikinya untuk wifi, LAN, dll.)
Adrian Mouat
Pastikan Anda ingat untuk mengikat port 5000 ke penampung Anda dengan -p 5000:5000bendera dengan docker runperintah Anda .
T Loch.
40

Saat menggunakan flaskperintah alih-alih app.run, Anda dapat memberikan --hostopsi untuk mengubah host. Garis di Docker adalah:

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

atau

CMD flask run --host 0.0.0.0
Marku
sumber
2
Terima kasih banyak atas solusi ini, saya memiliki masalah yang sama, tahukah Anda apa alasannya mengapa app.run(host="0.0.0.0") tidak berhasil? Saya juga membuat posting untuk pertanyaan ini: stackoverflow.com/q/53133350/3279996
xirururu
1
Pada catatan ini, pastikan untuk tidak menggunakan python run.py --host=0.0.0.0 . Itu membuat saya sesekali karena konvensi penamaan saya. Kode itu akan tampak berfungsi tetapi server akan berjalan di host lokal.
Braden Holt
1
Bukankah ini menjalankan server flask built-in, yang tidak dimaksudkan untuk lingkungan produksi?
code_dredd
Ini bagus, untuk alasan apapun hampir semua info Flask-with-Docker gagal menggunakan Flask CLI, yang mana afaik adalah cara Flask 1.0 untuk memulai sebuah aplikasi.
Zach Valenta
3
Di sini, di tahun 2020 dengan Flask 1.1.1 dengan app.run(host="0.0.0.0")kegagalan dan CMD ["flask", "run", "--host", "0.0.0.0" ]bekerja seperti juara.
Joe
2

Container Docker Anda memiliki lebih dari satu antarmuka jaringan. Misalnya, penampung saya memiliki yang berikut:

$ 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

jika Anda menjalankan docker network inspect bridge, Anda dapat melihat bahwa penampung Anda terhubung ke jembatan itu dengan antarmuka kedua pada keluaran di atas. Bridge default ini juga terhubung ke proses Docker di host Anda.

Oleh karena itu Anda harus menjalankan perintah:

CMD flask run --host 172.17.0.2

Untuk mengakses aplikasi Flask Anda yang berjalan di container Docker dari mesin host Anda. Ganti 172.17.0.2dengan alamat IP tertentu dari wadah Anda.

Bert
sumber
2

Untuk membangun jawaban lain:

Bayangkan Anda memiliki dua komputer. Setiap komputer memiliki antarmuka jaringan (misalnya WiFi), yang merupakan IP publiknya. Setiap komputer memiliki antarmuka loopback / localhost, di 127.0.0.1. Artinya "hanya komputer ini".

Jika Anda terdaftar di 127.0.0.1 di komputer A, Anda tidak akan berharap dapat menyambung ke itu melalui 127.0.0.1 saat menjalankan di komputer B. Lagi pula, Anda diminta untuk mendengarkan di alamat pribadi lokal komputer A.

Docker adalah pengaturan serupa; secara teknis ini adalah komputer yang sama, tetapi kernel Linux mengizinkan setiap container untuk berjalan dengan tumpukan jaringannya sendiri yang terisolasi. Jadi 127.0.0.1 di penampung sama dengan 127.0.0.1 di komputer yang berbeda dari host Anda — Anda tidak dapat menyambungkannya.

Versi yang lebih panjang, dengan diagram: https://pythonspeed.com/articles/docker-connection-refused/

Itamar Turner-Trauring
sumber
0

Pertama-tama dalam skrip python Anda, Anda perlu mengubah kode

app.run()

untuk

app.run(host="0.0.0.0")

Kedua, Dalam file buruh pelabuhan Anda, baris terakhir harus seperti

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

Dan pada mesin host jika 0.0.0.0:5000tidak berfungsi maka Anda harus mencobanyalocalhost:5000

Catatan - Perintah CMD harus benar. Karena perintah CMD menyediakan default untuk mengeksekusi kontainer.

Nivedita Shah
sumber