Series về Docker trong thực thành & sản xuất - Network trong Docker

Series về Docker trong thực thành & sản xuất - Network trong Docker

Những mẩu tin ngắn hàng ngày dành cho bạn
  • Đây! Một vấn đề mà từ xưa đến nay mình cứ thắc mắc mãi, và cho đến hôm qua thì mọi thứ đã sáng tỏ.

    Bình thường mọi người dùng height: 100vh để đặt chiều cao bằng với viewport của màn hình. Trên máy tính thì không vấn đề gì, thậm chí giả lập kích thước của điện thoại thông minh thì mọi thứ vẩn ổn. Nhưng khi mở trên điện thoại thì height 100vh lúc nào cũng vượt quá viewport. Ủa!? Là sao???

    Lý giải cho điều này là do trên thiết bị di động có cách tính viewport khác với máy tính. Nó thường bị can thiệp hay ảnh hưởng bởi thanh địa chỉ, thanh điều hướng của nền tảng mà bạn đang sử dụng. Vậy nên nếu muốn 100vh trên di động đúng bằng viewport thì cần phải làm thêm một bước thiết lập lại viewport.

    Dễ lắm, đầu tiên cần tạo một css variable --vh ở ngay thẻ script đầu trang.

    function updateViewportHeight() { const viewportHeight = globalThis.innerHeight; document.documentElement.style.setProperty('--vh', `${viewportHeight * 0.01}px`); } updateViewportHeight(); window.addEventListener('resize', updateViewportHeight);

    Sau đó thay vì dùng height: 100vh thì chuyển thành height: calc(var(--vh, 1vh) * 100). Thế là xong.

    » Xem thêm
  • Cả ngày hôm nay mình dành thời gian để làm giao diện tiếp thị cho gói hội viên của 2coffee.dev. Vậy là cuối cùng thì cũng chính thức đi vào vào con đường mà 5 năm trước cũng không ngờ đến được: "Bán một cái gì đó". Người ta thường nói "Cho đi để nhận lại", bên cạnh đó cũng có câu "Nếu giỏi một cái gì đó, đừng làm nó miễn phí". Nếu theo dõi đủ lâu, bạn đọc sẽ thấy chẳng có gì mình giấu giếm. Biết gì viết nấy, và đôi khi nhờ viết ra mà nhận lại được sự góp ý của độc giả. Từ đó giúp mình hoàn thiện bản thân nhiều hơn.

    Membership là tính năng mà mình sắp sửa giới thiệu. Trở thành hội viên của blog, bạn sẽ có một số đặc quyền nhất định, ví dụ như truy cập vào các bài viết chỉ dành riêng cho hội viên. Các bài viết này về các chủ đề chuyên sâu và được hệ thống hoá sao cho dễ đọc và dễ nắm bắt nhất. Qua đó cung cấp thêm nhiều kiến thức và trau dồi kỹ năng cho bạn đọc.

    Để đạt được đến ngày hôm nay là công rất lớn của các bạn đọc giả, của những người yêu mến 2coffee.dev. Nhờ các bạn mà blog mới có ngày hôm nay. Bên cạnh đó, bản thân mình cũng phải thay đổi liên tục, phải vượt ra khỏi vùng an toàn, làm những điều mà trước nay không dám. Dù sao đi nữa thì đây cũng mới là khởi đầu cho mọi sự gian nan. Nhưng đừng bao giờ nản nha các bạn ơi 😄

    » Xem thêm
  • Ngày nay, 1 triệu (1M) tác vụ đồng thời sẽ tiêu tốn bao nhiêu bộ nhớ? Đó là câu hỏi của hez2010 và anh đã quyết định đi tìm câu trả lời, bằng cách thử nghiệm một chương trình đơn giản trên nhiều ngôn ngữ lập trình khác nhau: How Much Memory Do You Need in 2024 to Run 1 Million Concurrent Tasks?

    Tóm tắt lại thì Rust vẫn vô đối, nhưng vị trí thứ 2 mới làm tôi cảm thấy ngạc nhiên 😳

    » Xem thêm

Vấn đề

Một trong những lý do khiến docker trở nên mạnh mẽ là hệ thống network hỗ trợ kết nối các container với nhau rất tốt, thậm chí chúng còn không quan tâm đến liệu có đang chạy trong môi trường của docker hay không, hay nền tảng máy chủ là gì.

Hiểu nôm na tức là một container có thể kết nối nhau hay đến một ứng dụng đang chạy ngoài docker mà không cần biết là docker for Linux, Windows hay MacOS.

Để tìm hiểu chi tiết hơn, mời các bạn theo dõi tiếp bài viết dưới đây nhé!

Network drivers

Docker cung cấp một số network drivers tuỳ theo mục đích sử dụng khác nhau:

  • bridge: đây là driver mặc định khi tạo một network nếu bạn không chỉ định một driver nào. drive này cho phép các container có thể giao tiếp với nhau nếu chúng đều nằm trong mạng này.
  • host: driver này cho phép các container sử dụng trực tiếp network của máy chủ docker. Tức là container sẽ không dùng network do docker cung cấp nữa mà dùng luôn network của máy chủ.
  • overlay: kết nối nhiều máy chủ docker với nhau thông qua chế độ swarm, các máy chủ docker có thể chạy trên bất kì nền tảng nào nhưng các container bên trong đó đều có thể giao tiếp với nhau.
  • none: đúng như tên gọi driver này đưa container của bạn về thời chưa có internet.

Ngoài ra còn có macvlan và các plugin của bên thứ ba mà trong phạm vi bài viết này tôi sẽ không nói đến. Bạn đọc quan tâm có thể tìm hiểu thêm trên trang chủ của docker.

Tạo một network

Docker cung cấp các lệnh để chúng ta có thể dễ dàng tạo một network.

$ docker network create -d bridge estacks-network --attachable

Tôi vừa tạo một network có tên là estacks-network với driver bridge. Cờ -d cho phép chỉ định các loại driver mà docker hỗ trợ. --attachable cho phép các container có thể kết nối vào network theo cách thủ công (dùng lệnh).

Để tạo mới một container và chỉ định nó kết nối vào network:

$ docker run --network estacks-network --name nginx -d nginx

Để kết nối một container có sẵn từ trước vào network:

$ docker network connect estacks-network mysql

Trong đó mysql là tên của container.

Có rất là nhiều lệnh khác mà mình không thể liệt kê hết ở đây được, các bạn có thể tham khảo thêm ở trang docker network để biết thêm chi tiết và cách sử dụng của chúng.

Cách sử dụng các driver trong mỗi trường hợp

Có một điều chắc chắn rằng các container muốn giao tiếp được với nhau thì chúng phải nằm trong cùng một mạng. Giao tiếp ở đây tức là chúng có khả năng trao đổi dữ liệu với nhau. Vì thế khi triển khai ứng dụng, nếu gặp vấn đề về kết nối thì bạn nên kiểm tra các vấn đề về network có trục trặc gì không.

Có một số cách để triển khai các container và giúp chúng có thể giao tiếp với nhau. Tôi sẽ gợi ý cho bạn một số cách mà tôi hay dùng dưới đây.

Triển khai các container độc lập

Ví dụ bạn chỉ đơn giản là muốn chạy một container mysql để làm cơ sở dữ liệu cho môi trường phát triển thì bạn chỉ cần dùng lệnh docker run:

$ docker run --name mysql -d mysql

Khi không chỉ định network container sẽ mặc định chạy ở bridge, nó được cấp một địa chỉ ip cố định ở bên trong network đó. Bất kì container nào chạy trong bridge sẽ gọi được đến ip của nhau:

$ docker inspect mysql
{
  ...
  "NetworkSettings": {
    ...
    "Networks": {
      "bridge": {
        "IPAMConfig": null,
        "Links": null,
        "Aliases": null,
        "NetworkID": "22a978aa722c09d9636cfcc4e6dedb4c788cf839421201a00a004596e812f0e1",
        "EndpointID": "a72743fdd788e759ed3358d3dd043122be08d5f5dcc8cd20144e55d7161f433c",
        "Gateway": "172.17.0.1",
        "IPAddress": "172.17.0.3",
        "IPPrefixLen": 16,
        "IPv6Gateway": "",
        "GlobalIPv6Address": "",
        "GlobalIPv6PrefixLen": 0,
        "MacAddress": "02:42:ac:11:00:03",
        "DriverOpts": null
      }
    }
  }
}

Mẹo: Sử dụng lệnh docker inspect để xem thông tin chi tiết của một container.

Như trên bạn có thể thấy mysql đang có địa chỉ ip là 172.17.0.3. Bây giờ, giả sử tôi sẽ khởi tạo thêm một container nginx cũng sử dụng bridge, truy cập vào trong container đó để thử ping đến địa chỉ 172.17.0.3 xem có nhận được gì không nhé:

$ docker run -d --name nginx nginx
$ docker exec -it nginx bash
root@02d4d43a19fd:/# ping 172.17.0.3
PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data.
64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.045 ms
64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.038 ms
64 bytes from 172.17.0.3: icmp_seq=3 ttl=64 time=0.035 ms
64 bytes from 172.17.0.3: icmp_seq=4 ttl=64 time=0.035 ms
^C
--- 172.17.0.3 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 115ms
rtt min/avg/max/mdev = 0.035/0.038/0.045/0.006 ms

Các bạn thấy đấy, do chúng cùng nằm trong mạng bridge nên nếu biết địa chỉ ip thì có thể giao tiếp được với nhau rồi.

Tuy nhiên các container như trên chỉ có thể gọi nhau nếu như chúng cùng nằm trong một mạng, nếu như tôi sử dụng termial thử ping đến mysql thì sẽ không nhận được bất kì phản nào nào. Tại sao vậy?

Bởi vì termial của tôi không được kết nối vào mạng bridge của docker, để làm được điều đó, docker cung cấp một cơ chế mà các bạn có thể đã biết rồi đó là expose port của mysql container ra ngoài máy chủ. Hiểu đơn giản đó là hành động mapping port của mysql ra một port khác trong máy chủ rồi từ port đó có thể kết nối đến container.

$ docker run -d --name mysql2 -p 3306:3307 mysql
$ telnet localhost 3307

Cờ -p 3306:3307 tức là expose cổng 3306 của container ra cổng 3307 của máy chủ, 3307 sẽ là cổng để giao tiếp với mysql trong container. Lúc này tôi có thể sử dụng máy chủ mysql thông qua localhost:3307.

Tôi muốn container dùng luông mạng của máy chủ docker?

Thay vì sử dụng cờ -p để expose từng port có trong docker, tôi có thể chạy container ở host. Khi chỉ định container chạy ở host nó sẽ không bị ràng buộc bởi mạng của docker nữa. Ví dụ:

$ docker run --network host --name mysql -d mysql

Ở terminal tôi thử telnet đến cổng 3306:

$ telnet localhost 3306
Trying ::1...
Connected to localhost.
Escape character is '^]'.

Docker for Windows hay MacOS bản chất là chạy trong một máy ảo Linux, vì thế khi sử dụng host thì network được docker sử dụng ở đây là network của máy ảo. Vì thế giả sử khi bạn dùng Windows mà muốn telnet đến cổng 3306 của container trên mà sử dụng localhost sẽ không được:

$ telnet localhost 3306
Trying ::1...
telnet: connect to address ::1: Connection refused

Thay vì localhost, bạn có thể thử sử dụng địa chỉ IP của máy ảo đang chạy docker.

Container trong docker-compose thì sao?

Tôi đã có một bài viết về Docker compose để khởi động nhiều services.

Hãy để ý trong file docker-compose.yml, mỗi service muốn có thể giao tiếp được với nhau thì chúng phải cần nằm trong networks, networks này là không giới hạn và bạn có thể kết nối các services với nhau tuỳ ý, chỉ cần nhớ một nguyên tắc "nằm trong cùng network" là được.

Networks được khai báo ở trong docker-compose.yml sẽ tồn tại ở trong stacks đó, tức là khi bạn start compose nó sẽ được tạo còn khi down compose thì nó sẽ bị xoá.
Bạn cũng có thể tạo một network sau đó join các services vào network đó.

$ docker network create my-network -d bridge --attachable

Cờ -d bridge chỉ định tạo network với driver bridge, --attachable cho phép các container có thể join vào thủ công. Xem thêm lệnh docker create tại trang của docker.

Trong docker-compose.yml.

version: "3.9"
services:
  mysql:
    ...
    networks:
      - my-network
    ...
  ...

networks:
  my-network:
    external: true

Cuối cùng, overlay có điều gì khác biệt?

Khi docker được triển khai ở chế độ swarm, nỗi node có thể sẽ có địa chỉ ip khác nhau, để làm giảm thiểu sự phức tạp trong giao tiếp giữa các container trên các node thì docker cung cấp overlay driver này.

Hiểu đơn giản là các container trên các node nếu cùng nằm trong một mạng overlay thì chúng có thể giao tiếp được với nhau.

Nếu các bạn chưa biết về docker swarm thì đừng lo, tôi đã lên kế hoạch cho bài viết tiếp theo trong series này.

Tổng kết

Network trong docker giúp cho việc giao tiếp giữa các docker dễ dàng hơn bao giờ hết vì bản chất của các container là độc lập với nhau. Ngoài ra docker cũng cung cấp khá là nhiều tuỳ chọn network driver tuỳ theo nhu cầu sử dụng của mỗi người trong đó có thể kể đến như bridge, host, overlay...

Có một nguyên tắc cần phải nhớ trong triển khai và gỡ lỗi đó là các container muốn giao tiếp được với nhau thì chúng phải cùng nằm trong một network.

Cao cấp
Hello

Tôi & khao khát "chơi chữ"

Bạn đã thử viết? Và rồi thất bại hoặc chưa ưng ý? Tại 2coffee.dev chúng tôi đã có quãng thời gian chật vật với công việc viết. Đừng nản chí, vì giờ đây chúng tôi đã có cách giúp bạn. Hãy bấm vào để trở thành hội viên ngay!

Bạn đã thử viết? Và rồi thất bại hoặc chưa ưng ý? Tại 2coffee.dev chúng tôi đã có quãng thời gian chật vật với công việc viết. Đừng nản chí, vì giờ đây chúng tôi đã có cách giúp bạn. Hãy bấm vào để trở thành hội viên ngay!

Xem tất cả

Đăng ký nhận thông báo bài viết mới

hoặc
* Bản tin tổng hợp được gửi mỗi 1-2 tuần, huỷ bất cứ lúc nào.
Author

Xin chào, tôi tên là Hoài - một anh Dev kể chuyện bằng cách viết ✍️ và làm sản phẩm 🚀. Với nhiều năm kinh nghiệm lập trình, tôi đã đóng góp một phần công sức cho nhiều sản phẩm mang lại giá trị cho người dùng tại nơi đang làm việc, cũng như cho chính bản thân. Sở thích của tôi là đọc, viết, nghiên cứu... Tôi tạo ra trang Blog này với sứ mệnh mang đến những bài viết chất lượng cho độc giả của 2coffee.dev.Hãy theo dõi tôi qua các kênh LinkedIn, Facebook, Instagram, Telegram.

Bạn thấy bài viết này có ích?
Không

Bình luận (0)

Nội dung bình luận...