Cách sử dụng Traefik như một Reverse Proxy cho Docker Containers trên Ubuntu 16.04

2 năm trước

 

Giới Thiệu 

Docker có thể là một cách hiệu quả để chạy các ứng dụng web trong sản xuất, nhưng bạn có thể muốn chạy nhiều ứng dụng trên cùng một máy chủ Docker. Trong trường hợp này, cần thiết lập reverse proxy  vì bạn chỉ muốn hiển thị cổng 80 và 443 .

Traefik  là một Docker-aware reverse proxy bao gồm bảng điều khiển giám sát của riêng nó. Trong hướng dẫn này, bạn sẽ sử dụng Traefik để định tuyến các yêu cầu tới hai container ứng dụng web khác nhau: một Wordpress container và một Adminer container ,mỗi bộ nói chuyện với một cơ sở dữ liệu MySQL. Bạn sẽ cấu hình Traefik để phục vụ mọi thứ qua HTTPS bằng cách sử dụng Let's Encrypt

 

Yêu Cầu

Để làm theo hướng dẫn này , bạn cần:

 

Bước 1 - Cấu hình và chạy Traefik

Dự án Traefik có một official Docker image, vì vậy chúng ta sẽ sử dụng nó để chạy Traefik trong Docker container.

Nhưng trước khi chúng ta bắt đầu và chạy container Traefik, chúng ta cần tạo một tệp cấu hình và thiết lập mật khẩu được mã hóa để truy cập trang tổng quan giám sát.

Chúng ta sẽ sử dụng tiện ích htpasswd để tạo mật khẩu được mã hóa này. Đầu tiên, cài đặt tiện ích, được bao gồm trong gói apache2-utils :

sudo apt-get install apache2-utils`
  •  

Sau đó tạo mật khẩu với htpasswd. Thay thế  secure_password bằng mật khẩu bạn muốn sử dụng cho người dùng quản trị viên Traefik:

htpasswd -nb admin secure_password

Đầu ra của chương trình sẽ trông như thế này:

output
admin:$apr1$ruca84Hq$mbjdMZBAG.KWn7vfN/SNK/
 

Bạn sẽ sử dụng đầu ra này trong tệp cấu hình Traefic để thiết lập Xác thực cơ bản HTTP cho bảng điều khiển kiểm tra và theo dõi Traefik health. Sao chép toàn bộ dòng đầu ra để bạn có thể dán nó sau.

Để cấu hình máy chủ Traefik, chúng ta sẽ tạo một tệp cấu hình mới có tên là traefik.toml bằng định dạng TOML. TOML là một ngôn ngữ cấu hình tương tự như các tệp INI, nhưng nó được chuẩn hóa. Tệp này cho phép chúng ta định cấu hình máy chủ Traefik và các tích hợp hoặc nhà cung cấp khác nhau chúng ta muốn sử dụng. Trong hướng dẫn này, chúng ta sẽ sử dụng ba nhà cung cấp có sẵn của Traefik: webdocker,và acme, được sử dụng để hỗ trợ TLS sử dụng Let's Encrypt.

nano traefik.toml

Đầu tiên, thêm hai điểm vào được đặt tên,  http and https, rằng tất cả các chương trình phụ trợ sẽ có quyền truy cập theo mặc định:

traefik.toml
defaultEntryPoints = ["http", "https"]

Chúng ta sẽ định cấu hình các điểm nhập http và https sau này trong tệp này.

Tiếp theo, định cấu hình nhà cung cấp web, cung cấp cho bạn quyền truy cập vào giao diện trang tổng quan. Đây là nơi bạn sẽ dán đầu ra từ lệnh htpasswd:

traefik.toml
...
[web]
address = ":8080"
[web.auth.basic]
users = ["admin:your_encrypted_password"]

Trang tổng quan là một ứng dụng web riêng biệt sẽ chạy trong container Traefik. Chúng ta thiết lập bảng điều khiển để chạy trên cổng 8080.

Phần  web.auth.basicđịnh cấu hình Xác thực cơ bản HTTP cho trang tổng quan. Sử dụng đầu ra từ lệnh htpasswd bạn vừa chạy cho giá trị của mục nhập users. Bạn có thể chỉ định thông tin đăng nhập bổ sung bằng cách tách chúng bằng dấu phẩy.

Tiếp theo, xác định các điểm vào. Phần entryPoints cấu hình các địa chỉ mà Traefik và các container proxy có thể lắng nghe. Thêm những dòng này vào tệp:

traefik.toml
...
[entryPoints]
[entryPoints.http]
address = ":80"
[entryPoints.http.redirect]
entryPoint = "https"
[entryPoints.https]
address = ":443"
[entryPoints.https.tls]

Điểm vào http xử lý cổng 80, trong khi điểm nhập https sử dụng cổng 443 cho TLS / SSL. Chúng ta tự động chuyển hướng tất cả traffic trên cổng 80 đến điểm nhập https để buộc các kết nối an toàn cho tất cả các yêu cầu.

Cuối cùng, thêm phần này để cấu hình Let's Encrypt hỗ trợ cho Traefik:

traefik.toml
...
[acme]
email = "your_email@example.com"
storage = "acme.json"
entryPoint = "https"
onHostRule = true
onDemand = false

Phần này được gọi là acme vì ACME là tên của giao thức được sử dụng giao tiếp với Let's Encrypt để quản lý chứng chỉ. Để có Traefik tạo chứng chỉ cho máy chủ, chúng ta sẽ đặt khóa  email  thành địa chỉ email của bạn. Sau đó xác định rằng lưu trữ thông tin mà chúng ta sẽ nhận được từ Let's Encrypt trong một tệp JSON có tên là acme.json. Phím  entryPoint cần trỏ tới cổng xử lý điểm nhập 443, trong trường hợp của chúng ta là điểm nhập https.

Hai khóa cuối cùng, onHostRule và onDemand, ra lệnh  Traefik nên tạo các chứng chỉ như thế nào. Chúng ta muốn tìm nạp các chứng chỉ ngay sau khi các container với tên máy chủ chỉ định được tạo và đó là những gì mà cài đặt onHostRule sẽ thực hiện. Cài đặt  onDemand sẽ cố gắng tạo chứng chỉ lần đầu tiên mà yêu cầu được thực hiện. Điều này sẽ làm chậm yêu cầu đầu tiên và rất đáng chú ý đối với khách truy cập, vì vậy hãy tránh điều đó.

Lưu tệp và thoát khỏi trình chỉnh sửa. Với tất cả cấu hình này tại chỗ, chúng ta có thể kích hoạt Traefik.

 

Bước 2 – Chạy Container Traefik

Tiếp theo, tạo một mạng Docker cho proxy để chia sẻ với các container. Mạng Docker là cần thiết để chúng ta có thể sử dụng nó với các ứng dụng đang chạy bằng cách sử dụng Docker Compose. Hãy gọi mạng nàyproxy.

docker network create proxy

 

Khi container Traefik bắt đầu, chúng ta sẽ thêm nó vào mạng này. Sau đó, hãy thêm các container bổ sung vào mạng này sau đó cho Traefik để proxy.

Tiếp theo, tạo một tệp rỗng sẽ giữ thông tin mã hóa . Chúng ta sẽ chia sẻ điều này vào container để Traefik có thể sử dụng nó:

touch acme.json

Sau đó, khóa các quyền trên tệp này để chỉ người dùng root có thể đọc và ghi vào tệp này. Nếu bạn không làm điều này, Traefik sẽ không khởi động được.

chmod 600 acme.json

Cuối cùng, tạo container Traefik bằng lệnh này:

docker run -d \
-v /var/run/docker.sock:/var/run/docker.sock \
-v $PWD/traefik.toml:/traefik.toml \
-v $PWD/acme.json:/acme.json \
-p 80:80 \
-p 443:443 \
-l traefik.frontend.rule=Host:monitor.example.com \
-l traefik.port=8080 \
--network proxy \
--name traefik \
traefik:1.3.6-alpine --docker

Lệnh này hơi dài nên hãy chia nhỏ nó đi.

Chúng ta sử dụng chỉ báo-d để chạy container dưới nền dưới dạng một daemon. Sau đó, chia sẻ tệp docker.sock vào container để quy trình Traefik có thể lắng nghe những thay đổi đối với containers. Chúng ta cũng chia sẻ tệp cấu hình traefik.toml và tệp acme.json mà chúng ta đã tạo vào container.

Tiếp theo, chúng ta map các cổng:80 và:443  của máy chủ Docker đến cùng các cổng trong containerTraefik để Traefik nhận tất cả traffic HTTP và HTTPS đến máy chủ.

Sau đó,  thiết lập hai label Docker cho Traefik hướng traffic đến tên máy chủ monitor.example.com đến cổng:8080 trong container Traefik, hiển thị bảng theo dõi.

Chúng ta đặt mạng của container thành proxy và đặt tên cho container traefik.

Cuối cùng, chúng ta sử dụng traefik:1.3.6-alpine cho container này, vì nó nhỏ.

ENTRYPOINT của hình ảnh Docker là lệnh luôn chạy khi container được tạo từ hình ảnh. Trong trường hợp này, lệnh là nhị phân traefik trong container. Bạn có thể chuyển đối số bổ sung cho lệnh đó khi bạn khởi chạy container. Trong trường hợp của chúng ta, chúng ta chuyển đối số --docker tới ENTRYPOINT để đảm bảo rằng nhà cung cấp docker được đăng ký với các thiết lập mặc định.NHà cung cấp docker cho phép Traefik hoạt động như một proxy ở phía trước các container Docker. Cấu hình mặc định của nhà cung cấp Docker hoạt động tốt cho chúng ta, vì vậy  không cần cấu hình nó trong traefik.toml .

Vớicontainer đã bắt đầu, bây giờ bạn có trang tổng quan, bạn có thể truy cập để xem tình trạng của container. Bạn cũng có thể sử dụng bảng điều khiển này để trực quan hóa giao diện người dùng và phần phụ trợ mà Traefik đã đăng ký. Truy cập trang tổng quan giám sát bằng cách trỏ trình duyệt của bạn đến https://monitor.example.com. Bạn sẽ được nhắc nhập tên người dùng và mật khẩu của mình, đó là quản trị viên và mật khẩu bạn đã định cấu hình trong Bước 1.

Sau khi đăng nhập ,. bạn sẽ thấy một giao diện tương tự như thế này:

Empty Traefik dashboard

Hiện chưa có nhiều thứ để xem, nhưng hãy để cửa sổ này mở và bạn sẽ thấy nội dung thay đổi khi bạn thêm container cho Traefik để làm việc.

Bây giờ chúng ta có proxy Traefik chạy, được cấu hình để làm việc với Docker và sẵn sàng giám sát các container Docker khác. Hãy bắt đầu một số container cho Traefik để hoạt động như một proxy.

Bước 3 - Đăng ký Containers với Traefik

Với container Traefik đang chạy, bạn đã sẵn sàng chạy các ứng dụng phía sau nó. Hãy khởi động các container dưới đây sau Traefik:

  1. Một blog sử dụng  official Wordpress image.
  2. Một máy chủ quản lý cơ sở dữ liệu sử dụng official Adminer image.

Chúng ta sẽ quản lý cả hai ứng dụng này với Docker Compose bằng cách sử dụng một tệp docker-compose.yml :

nano docker-compose.yml
  •  

Thêm các dòng sau vào tệp để chỉ định phiên bản và mạng mà chúng ta sẽ sử dụng:

docker-compose.yml
version: "3"
networks:
proxy:
external: true
internal:
external: false

Chúng ta sử dụng Docker Compose phiên bản 3 vì đây là phiên bản chính mới nhất của định dạng tệp Compose.

Để Traefik nhận ra các ứng dụng của chúng ta, chúng phải là một phần của cùng một mạng và vì chúng ta đã tạo mạng theo cách thủ công, kéo nó bằng cách chỉ định tên mạng củaproxy  và đặt external  đến true . Sau đó,  xác định một mạng khác để  kết nối các container được tiếp xúc với một container cơ sở dữ liệu mà chúng ta sẽ không hiển thị thông qua Traefik. Chúng ta sẽ gọi mạng này là internal.

Tiếp theo, xác định từng services . Hãy bắt đầu với container blog, chúng ta sẽ dựa trên hình ảnh WordPress chính thức. Thêm cấu hình này vào tệp:

docker-compose.yml
version: "3"
...
services:
blog:
image: wordpress:4.7.5-apache
environment:
WORDPRESS_DB_PASSWORD:
labels:
- traefik.backend=blog
- traefik.frontend.rule=Host:blog.example.com - traefik.docker.network=proxy
- traefik.port=80
networks:
- internal
- proxy
depends_on:
- mysql

Khóa environment cho phép bạn chỉ định các biến môi trường sẽ được đặt bên trong container. Bằng cách không đặt giá trị cho WORDPRESS_DB_PASSWORD,chúng ta sẽ yêu cầu Docker Compose lấy giá trị từ trình bao và chuyển nó qua khi tạo container. Chúng ta sẽ định nghĩa biến môi trường này trong shell của chúng ta trước khi bắt đầu các container. Bằng cách này, chúng ta không mã hóa mật khẩu cứng vào tệp cấu hình.

Phần labels là nơi bạn chỉ định các giá trị cấu hình cho Traefik. Docker labels không làm bất cứ điều gì một mình, nhưng Traefik đọc những điều đó vì vậy nó biết cách để xử lý container. Dưới đây là những gì labels này thực hiện:

  • traefik.backend chỉ định tên của dịch vụ phụ trợ trong Traefik (trỏ đến container blog thực tế)..
  • traefik.frontend.rule=Host:blog.example.com yêu cầu Traefik kiểm tra máy chủ được yêu cầu và nếu nó khớp với mẫu của blog.example.com, nó sẽ định tuyến traffic đến container blog.
  • traefik.docker.network=proxy chỉ định mạng nào sẽ xem xét cho Traefik để tìm IP nội bộ cho container này. Vì container Traefik của chúng ta có quyền truy cập vào tất cả thông tin Docker, nó có khả năng sẽ lấy IP cho mạng internal nếu chúng ta không chỉ định điều này.
  • traefik.port chỉ định cổng tiếp xúc mà Traefik nên sử dụng để định tuyến traffic đến container này.

Với cấu hình này, tất cả traffic được gửi đến cổng 80 của máy chủ Docker của chúng ta sẽ được định tuyến đến container blog.

Chúng ta gán container này cho hai mạng khác nhau để Traefik có thể tìm thấy nó qua mạng proxy và nó có thể giao tiếp với container cơ sở dữ liệu thông qua mạng internal.

Cuối cùng, khóa depends_on nói với Docker Compose rằng container này cần phải bắt đầu sau khi các phụ thuộc của nó đang chạy. Vì WordPress cần một cơ sở dữ liệu để chạy, chúng ta phải chạy container mysqlcủa mình trước khi bắt đầu container  blog của chúng ta.

Tiếp theo, cấu hình dịch vụ MySQL bằng cách thêm cấu hình này vào tệp của bạn:

docker-compose.yml
services:
...
mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD:
networks:
- internal
labels:
- traefik.enable=false

Chúng ta đang sử dụng hình ảnh chính thức của MySQL 5.7 cho container này. Bạn sẽ nhận thấy rằng  lại một lần nữa sử dụng một mụcenvironment không có giá trị. Các biến MYSQL_ROOT_PASSWORD và WORDPRESS_DB_PASSWORD sẽ cần phải được đặt thành cùng một giá trị để đảm bảo rằng container WordPress của chúng ta có thể giao tiếp với MySQL. Chúng ta không muốn để lộ các container mysql đếnTraefik hoặc thế giới bên ngoài,  chỉ định container này vào mạng internal. Vì Traefik có quyền truy cập vào socket Docker, quá trình này vẫn sẽ trưng ra một lối vào cho container mysql theo mặc định, vì vậy hãy thêm label traefik.enable=false để chỉ định rằng Traefik không nên để lộ container này.

Cuối cùng, thêm cấu hình này để xác định container Adminer:

docker-compose.yml
services:
...
adminer:
image: adminer:4.3.1-standalone
labels:
- traefik.backend=adminer
- traefik.frontend.rule=Host:db-admin.example.com - traefik.docker.network=proxy
- traefik.port=8080
networks:
- internal
- proxy
depends_on:
- mysql

Container này dựa trên hình ảnh Quản trị viên chính thức. Cấu hình network và depends_on cho container này khớp chính xác với những gì chúng ta đang sử dụng cho container blog.

Tuy nhiên, vì chúng ta đang hướng tất cả traffic đến cổng 80 trên máy chủ Docker  trực tiếp đến container blog, cần phải định cấu hình container này khác nhau để traffic  tạo đến container adminer. Dòng traefik.frontend.rule=Host:db-admin.example.com yêu cầu Traefik kiểm tra máy chủ được yêu cầu. Nếu nó khớp với mẫu của db-admin.example.com, Traefik sẽ định tuyến traffic tới container adminer.

Lưu tệp và thoát trình soạn thảo văn bản.

Tiếp theo, đặt giá trị trong trình bao của bạn cho các biến WORDPRESS_DB_PASSWORD và MYSQL_ROOT_PASSWORD trước khi bạn bắt đầu container của mình:

export WORDPRESS_DB_PASSWORD=secure_database_passwordexport MYSQL_ROOT_PASSWORD=secure_database_password

Thay thế secure_database_password bằng mật khẩu cơ sở dữ liệu bạn muốn.

Với các biến này được đặt, hãy chạy các containers bằng cách sử dụng docker-compose:

docker-compose up -d

Bây giờ hãy nhìn vào bảng điều khiển quản trị Traefik. Bạn sẽ thấy rằng có một backendvà một frontend  cho hai máy chủ được tiếp xúc:

Populated Traefik dashboard

Điều hướng đến blog.example.com, thay thế example.com bằng tên miền của bạn. Bạn sẽ được chuyển hướng đến một kết nối TLS và bây giờ có thể hoàn thành thiết lập Wordpress:

WordPress setup screen

Bây giờ, hãy truy cập Quản trị viên bằng cách truy cập db-admin.example.com trong trình duyệt của bạn, một lần nữa thay thế example.com bằng tên miền của bạn. Container mysql không được tiếp xúc với thế giới bên ngoài, nhưng container  adminer có quyền truy cập vào nó thông qua mạng Docker internal mà chúng chia sẻ bằng cách sử dụng tên container  mysql như một tên máy chủ.

Trên màn hình đăng nhập Adminer, sử dụng tên người dùng  root, sử dụng  mysql cho server và sử dụng giá trị bạn đặt cho MYSQL_ROOT_PASSWORD cho mật khẩu. Sau khi đăng nhập, bạn sẽ thấy giao diện người dùng Adminer:

Adminer connected to the MySQL database

Cả hai trang web hiện đang hoạt động và bạn có thể sử dụng trang tổng quan tại monitor.example.com để theo dõi các ứng dụng của mình.

 

Kết Luận 

Trong hướng dẫn này, bạn đã cấu hình Traefik cho các yêu cầu proxy tới các ứng dụng khác trong các container Docker.

Cấu hình khai báo của Traefik ở cấp độ ứng dụng giúp dễ dàng định cấu hình nhiều dịch vụ hơn và không cần phải khởi động lại container traefik khi bạn thêm ứng dụng mới vào proxy traffic từ khi Traefik thông báo những thay đổi ngay lập tức thông qua tệp socket Docker.

Để tìm hiểu thêm về những gì bạn có thể làm với Traefik, hãy truy cập tài liệu chính thức của Traefik.