Cách khắc phục lỗi 'Timeout when waiting for host:port' trong Ansible

beginner🔧 Ansible2026-07-12| Linux (Ubuntu/CentOS/Debian), Ansible 2.9+, nhắm đến các dịch vụ như MySQL, PostgreSQL, hoặc Nginx.

Error Message

FAILED! => {"elapsed": 30, "msg": "Timeout when waiting for 127.0.0.1:3306"}
#ansible#devops#khắc phục lỗi#linux#tự động hóa

TL;DR: Cách khắc phục nhanh

Phần lớn các trường hợp, lỗi này xảy ra do một dịch vụ—như ứng dụng Java nặng hoặc cơ sở dữ liệu—mất nhiều thời gian để khởi tạo hơn khoảng thời gian 30 giây mặc định của Ansible. Để khắc phục, bạn cần cho dịch vụ thêm thời gian bằng cách tăng timeout và thêm delay.

- name: Đợi MySQL sẵn sàng
  wait_for:
    host: 127.0.0.1
    port: 3306
    delay: 10     # Không kiểm tra trong 10 giây đầu tiên
    timeout: 90   # Cho phép tối đa tổng cộng 90 giây
    state: started

Trong cấu hình này, Ansible sẽ tạm dừng 10 giây, sau đó thăm dò cổng cho đến khi nó mở hoặc cho đến khi bộ đếm 90 giây kết thúc.

Tại sao lỗi này xảy ra?

Khi bạn thấy "elapsed": 30 trong nhật ký lỗi, điều đó có nghĩa là module wait_for đã đạt đến giới hạn thời gian mà không thiết lập được kết nối TCP thành công. Đây không hẳn là lỗi trong mã của bạn; thường đó chỉ là sự không khớp về thời gian.

Các nguyên nhân phổ biến bao gồm:

  • Migration cơ sở dữ liệu: Một container MySQL hoặc PostgreSQL mới có thể đang bận tạo bảng hoặc nhập bản sao lưu SQL 500MB trong lần khởi động đầu tiên.
  • Khởi động JVM: Các công cụ dựa trên Java như Jenkins hoặc Elasticsearch thường mất 45–120 giây để liên kết hoàn toàn với cổng của chúng.
  • Tranh chấp tài nguyên: Trên một VPS giá rẻ 5$/tháng với CPU hạn chế, các dịch vụ khởi động chậm hơn đáng kể so với máy phát triển cục bộ.
  • Lỗi 'Silent Crash': Dịch vụ đã cố khởi động nhưng thất bại do lỗi đánh máy trong tệp cấu hình và thoát ra. Vì tiến trình không chạy, cổng sẽ không bao giờ mở.

Các chiến lược hiệu quả để khắc phục lỗi Timeout

1. Tăng Timeout cho các tác vụ nặng

Nếu dịch vụ của bạn hoạt động bình thường nhưng chậm, hãy mở rộng khung thời gian. Đối với các ứng dụng lớn như GitLab hoặc các pod phức tạp do Kubernetes quản lý, timeout 300 giây (5 phút) là lựa chọn an toàn hơn so với mặc định.

- name: Đợi ứng dụng cũ khởi động chậm
  wait_for:
    port: 8080
    timeout: 300

2. Sử dụng 'delay' để giảm nhiễu nhật ký

Việc gửi liên tiếp các yêu cầu kết nối tới một cổng ngay sau lệnh khởi động systemd là không hiệu quả. Nó thậm chí có thể làm đầy nhật ký dịch vụ với các lỗi đặt lại kết nối (connection reset). Thiết lập delay: 15 yêu cầu Ansible đợi 15 giây trước khi thực hiện lần thử đầu tiên.

- name: Khởi động ứng dụng và đợi
  service:
    name: my_custom_app
    state: started

- name: Đợi cổng 8443
  wait_for:
    port: 8443
    delay: 15
    timeout: 120

3. Kiểm tra trạng thái tiến trình trước

Đừng đợi một cổng nếu bản thân dịch vụ đã bị sập. Bạn có thể đăng ký kết quả của tác vụ khởi động dịch vụ để xem liệu nó có thực sự tiếp tục chạy hay không.

- name: Khởi động PostgreSQL
  service:
    name: postgresql
    state: started
  register: pg_start_result

- name: Dừng sớm nếu dịch vụ không chạy
  fail:
    msg: "Postgres không thể khởi động!"
  when: pg_start_result.state != 'started'

- name: Đợi cổng Postgres
  wait_for:
    port: 5432
    timeout: 60

4. Kiểm tra liên kết mạng (Network Bindings)

Dịch vụ của bạn có đang lắng nghe đúng nơi bạn nghĩ không? Nếu ứng dụng được cấu hình để chỉ liên kết với IP riêng 10.0.0.5, nhưng tác vụ Ansible của bạn lại kiểm tra 127.0.0.1, nó sẽ luôn bị timeout. Chạy lệnh sau trên máy chủ đích để xác minh địa chỉ lắng nghe thực tế:

ss -tulpn | grep :3306

Nếu đầu ra hiển thị 0.0.0.0:3306, nghĩa là nó đang lắng nghe trên tất cả các interface. Nếu nó hiển thị một IP cụ thể, hãy đảm bảo tham số host: trong Ansible khớp chính xác với IP đó.

Cách xác nhận bản sửa lỗi

Chạy playbook của bạn với cờ -v để xem thời gian nội bộ của module. Điều này giúp bạn hiểu bạn đang ở gần giới hạn như thế nào.

ansible-playbook site.yml -v

Một lần chạy thành công sẽ trông như thế này:

ok: [db_server] => {
    "changed": false,
    "elapsed": 22,
    "port": 3306,
    "state": "started"
}

Trong kịch bản này, "elapsed": 22 cho thấy dịch vụ mất 22 giây để khởi động. Vì con số này gần với mức mặc định 30 giây, bạn nên đặt timeout thành 60 để dự phòng cho các trường hợp tăng đột biến về I/O đĩa hoặc tải CPU trong tương lai.

Các lưu ý quan trọng cần chú ý

  • Firewall bên ngoài: Nếu Ansible đang chạy từ một máy điều khiển (control node) và kiểm tra một cổng từ xa, hãy đảm bảo AWS Security Group hoặc firewall phần cứng không chặn lưu lượng truy cập.
  • Sự mơ hồ của Localhost: Trên một số hệ thống, localhost phân giải thành ::1 (IPv6). Nếu dịch vụ của bạn chỉ lắng nghe trên 127.0.0.1 (IPv4), hãy sử dụng địa chỉ IP rõ ràng thay vì hostname.

Related Error Notes