Hy vọng bạn sẽ không bao giờ thực sự cần đọc bài này, và bạn chỉ ở đây vì chán hoặc search sai kiểu. Hoặc bạn thực sự gặp issue nơi Docker container không còn Internet access, dù chúng hoạt động tốt, vừa rồi, và bạn không thay đổi gì môi trường.
Điều này nghe như một problem statement khá vague, nhưng đây là những gì tôi đối mặt out of the blue. Container của tôi không có network access, với lỗi kiểu Temporary failure resolving URL. Trông như issue với name resolution, và nó bug tôi extra, vì nó không supposed to happen. Nhưng chúng ta đang getting ahead of ourselves. Test host: Ubuntu với systemd - quan trọng cho sau. Hãy tiến hành từ từ.
Vấn đề chi tiết hơn
Bạn đã cấu hình Docker trên hệ thống. Nó chạy tốt. Bạn có multiple image, multiple container, thậm chí dùng advanced network rule, và mọi thứ dường như in perfect order. Sau đó, bạn nhận thấy bạn không còn làm được một số hoạt động trong container, như update hoặc cài package. Cách tốt nhất để debug là attach shell vào running container instance, như tôi đã giải thích trong intro guide. Thực tế, bên trong running container, bạn thấy gì đó như:
# apt-get update
Err:1 https://archive.ubuntu.com/ubuntu bionic InRelease
Temporary failure resolving 'archive.ubuntu.com'
0% [Connecting to security.ubuntu.com]
Điều này trông như DNS problem (name resolution). Container không thể figure out cách resolve domain name thành IP address, và do đó không thể connect đến server để lấy data, như update. Có hai issue ở đây. Thứ nhất, tại sao vấn đề nảy sinh out of the blue? Thứ hai, chúng ta cần thực sự fix network. Bây giờ, tôi muốn chỉ cho bạn cách troubleshoot này một cách elegant.
Giải pháp
Trước hết, hiểu tại sao issue xảy ra. Không có câu trả lời immediate, nhưng một số điều cần nhìn có thể bao gồm không chỉ môi trường immediate của bạn. Ví dụ, host của bạn có thể không thay đổi, nhưng network có thể - router, network policy, DNS server bản thân. Vì bạn không thể bình thường kiểm soát điều gì xảy ra bên ngoài setup immediate, cách tốt nhất để figure out issue ở đâu là làm step-by-step isolation của vấn đề.
- Nếu host system có network và không resolve được URL, bạn cần sort đó trước. Có khả năng lớn là vấn đề giữa host và destination, và bất kỳ network infrastructure nào ở giữa.
- Nếu host system có network và resolve URL đúng, issue nằm cụ thể ở cách Docker container resolve URL. Đây là nơi chúng ta cần focus tiếp.
- Check nếu Docker network interface up và running (với lệnh như
iphoặcifconfig). Nếu không, bạn sẽ cần fix đó trước trước khi đi bước tiếp.
ifconfig docker0
- Check nếu container instance có IP address. Nếu không, bạn sẽ cần fix đó.
docker inspect <container name or ID> | grep -i "ipaddr"
- Check nếu bạn có cùng kết quả bên trong container nếu có thể (
iphoặcifconfig). Nếu kết quả không match những gì bạn thấy ở lệnh trước, bạn sẽ cần fix đó. - Check nếu bạn ping được container từ bên ngoài (và ngược lại, nếu ping command available). Nếu ping works, đây probably là indication tốt rằng network configured correctly, và không có firewall rule block traffic (most likely).
Name Resolution
Nếu tất cả check này return không strange problem hoặc error, bước tiếp theo là focus vào DNS resolution. Cấu hình cho đó sẽ có trong file config /etc/resolv.conf. Điều này đúng cho cả physical instance Linux, VM và container. Bạn probably sẽ notice container dùng gì đó như:
...
# See man:systemd-resolved.service(8) for details about the supported modes
# of operation for /etc/resolv.conf.
search xyz
nameserver X.Y.Z.W
...
Địa chỉ IP nameserver most likely sẽ là external IP (giống ISP) hoặc localhost (127.0.0.X). Câu hỏi là: Chúng có match file /etc/resolv.conf của host không?
Câu trả lời là, bạn most probably có localhost defined trong /etc/resolv.conf của host. Bây giờ, thử điều đó trong container. Edit file resolv.conf và replace IP address trong dòng nameserver với giá trị match host = localhost. Nếu điều đó giải quyết issue, great. Nhưng most likely, nó won't.
Nhưng rồi, ở điểm này, bạn không có vấn đề với network connectivity trên host. Vì vậy, chúng ta cần figure out REAL address của DNS server trong môi trường của bạn. Và điều này phức tạp hơn bởi thực tế hầu hết modern Linux distro dùng systemd. Cốt truyện dày đặc.
Tìm DNS với systemd
Vâng. Chúng ta cần figure out nameserver là gì, và chúng ta sẽ cần dùng lệnh systemd cho đó. Most likely, nếu bạn có systemd trong hệ thống, bạn cũng dùng systemd-resolve, network name resolution manager và service. Cấu hình lưu dưới /etc/systemd/resolved.conf. Nhưng bạn cũng có thể lấy kết quả trên command line với lệnh systemd-resolve:
systemd-resolve --status
Link 3 (wlp59s0)
Current Scopes: DNS
LLMNR setting: yes
MulticastDNS setting: no
DNSSEC setting: no
DNSSEC supported: no
DNS Servers: 10.50.34.1
2001:64c:1462:b023::1
DNS Domain: dedoimedo
Chúng ta có gì đây? Nhiều thứ thú vị. Nhưng điều thực sự quan trọng là dòng đọc DNS Servers. Đây là những gì chúng ta muốn. Đặt địa chỉ IP này vào file /etc/resolv.conf của container và thử lại. Bạn nên có network hoạt động lại.
Tại sao vấn đề này lại xảy ra?
Bây giờ, chúng ta có thể discuss why again. Nếu bạn nhìn vào systemd-resolve documentation, có thể có thay đổi nào đó trong hệ thống (có thể thậm chí do regular update) mà selected mode of operation gây conflict với name resolution. Đặc biệt, nếu nhìn cách /etc/resolv.conf được handle, thì mode đầu tiên nói:
systemd-resolved maintains the /run/systemd/resolve/stub-resolv.conf file for compatibility with traditional Linux programs. This file may be symlinked from /etc/resolv.conf. This file lists the 127.0.0.53 DNS stub (see above) as the only DNS server. It also contains a list of search domains that are in use by systemd-resolved. The list of search domains is always kept up-to-date. Note that /run/systemd/resolve/stub-resolv.conf should not be used directly by applications, but only through a symlink from /etc/resolv.conf. This file may be symlinked from /etc/resolv.conf in order to connect all local clients that bypass local DNS APIs to systemd-resolved with correct search domains settings. This mode of operation is recommended.
Nếu một trong các link trong equation này broken, hoặc có gì đó thay đổi, có thể Docker service không thể really determine what gives, và bạn kết thúc với no name resolution. Vì vậy, resolution [sic] là cung cấp actual network DNS address, mà container có thể hiểu và dùng. Điều này hơi speculative về phía tôi, nhưng tôi nghĩ nó quite correct.
Kết luận
Xong rồi, another mystery demisted, another windscreen demystified. Hoặc cái gì đó. Tôi không thích half-magic solutions, nhưng khi bạn có super-complicated, layered system infrastructure, đôi khi solutions just as bad as the problem. Không phải ở chỗ chúng không fix issue - ở chỗ bạn có less visibility và control hơn bạn respectfully should. Nhưng đó là future of Linux - và everything IT - endless abstraction.
On topic, hy vọng little guide này cung cấp cho bạn relatively quick và painless fix cho container adventure của bạn. Nếu bạn dùng Docker, và name resolution không còn hoạt động bên trong container instance, có lẽ bạn nên test tips và tricks viết ở trên - và sau đó build image của riêng bạn với fix đúng chỗ, để bạn không cần fight này all over again. Và bạn đã có nó, the end.
Chúc vui.