Jenkins Learn
05. Agents & Distributed Builds

Inbound Agents

Thiết lập Jenkins agent chủ động kết nối về controller qua Remoting, WebSocket hoặc inbound TCP một cách an toàn và có thể vận hành.

Phạm vi và giả định

Trang này dành cho agent do đội vận hành kiểm soát, chủ động kết nối tới Jenkins controller. Ví dụ dùng Jenkins LTS, Java tương thích với LTS đó và một node lab; thay URL, tên node, CA và đường dẫn bằng giá trị của bạn. Không chạy các mẫu này trên agent production trước khi đã review network, phiên bản và trust boundary.

Inbound agent phù hợp khi controller không được phép mở SSH vào máy build, còn máy build có thể mở kết nối outbound đến controller. Điều này giải quyết chiều kết nối, không tự cấp một ranh giới bảo mật: Pipeline vẫn có thể chạy mã từ repository trên chính host agent đó.

Mục lục

Khi nào dùng inbound agent

Controller tạo queue, chọn node theo label và cấp executor; agent mới chạy checkout, test hoặc build. Với inbound agent, tiến trình Java trên agent mở kết nối tới controller. Vì vậy nó hợp với host nằm sau NAT, mạng chi nhánh hoặc policy chỉ cho phép outbound HTTPS. Bức tranh controller–agent, queue và executor được trình bày tại Tổng quan Jenkins, Kiến trúc Jenkins và Tổng quan về agents.

Không chọn inbound chỉ vì tên gọi. Nếu controller cần truy cập host để quản trị, SSH-launched agent có thể là lựa chọn phù hợp hơn; nếu workload cần môi trường ngắn hạn và cô lập, Kubernetes hoặc container provisioning có thể hợp lý hơn. Inbound mô tả hướng khởi tạo kết nối, không nói agent là permanent hay ephemeral, cũng không nói nó đáng tin cậy.

Không dùng hướng kết nối làm security boundary

Không chạy pull request từ fork, repository không tin cậy hoặc dependency chưa review trên agent tin cậy có workspace, network access hay credential của release. Tách pool, identity, filesystem và egress cho workload không tin cậy; label chỉ hỗ trợ scheduler, không phải ACL.

Mô hình kết nối và Jenkins Remoting

Jenkins Remoting là lớp giao tiếp của Jenkins giữa controller và agent. Tiến trình agent.jar xác thực danh tính node, thiết lập channel Remoting hai chiều, nhận tác vụ khi controller cấp executor và gửi log/trạng thái về controller. Agent không tự kéo một job bất kỳ từ controller: controller vẫn quyết định queue, label, executor và quyền của job.

Luồng kết nối

direction: right
host: "Host agent\nagent.jar + service account"
controller: "Jenkins controller\nnode config + queue"
process: Pipeline process
queue: Build Queue
host -> controller: Agent khởi tạo HTTPS/WSS hoặc TCP
controller -> host: Remoting lệnh, log, trạng thái
host -> process: Workspace, toolchain
controller -> queue: Chọn node theo label + executor
Host agentagent.jar + service accountJenkins controllernode config + queuePipeline processBuild Queue Agent khởi tạo HTTPS/WSS hoặc TCPRemoting lệnh, log, trạng tháiWorkspace, toolchainChọn node theo label + executor
Host agentagent.jar + service accountJenkins controllernode config + queuePipeline processBuild Queue Agent khởi tạo HTTPS/WSS hoặc TCPRemoting lệnh, log, trạng tháiWorkspace, toolchainChọn node theo label + executor
Luồng kết nối

Secret gắn agent với node đã cấu hình; URL gắn agent với controller mong đợi. Sau khi channel hoạt động, controller có thể gửi work qua channel đó, nhưng agent không cần một inbound connection từ controller vào host. Điều này đặc biệt quan trọng khi viết firewall rule: mở luồng theo agent → controller, không đảo chiều chỉ vì controller là bên điều phối.

Inbound TCP listener và port 50000

Inbound TCP dùng một TCP listener cho agent trên controller. Port mặc định thường được minh họa là 50000, nhưng port thực tế là giá trị đã chọn trong Manage Jenkins → Security → Agents hoặc cấu hình tương đương của controller. Với môi trường production, dùng port cố định đã được phê duyệt thay vì port ngẫu nhiên, rồi allowlist nguồn agent ở firewall/VPN/security group.

TransportKết nối mạngFirewall cần mởKhi phù hợp
Inbound TCPAgent → controller TCP listener, ví dụ 50000Egress từ agent và ingress vào controller trên port TCP đã cấu hìnhCó đường TCP riêng, không đi qua HTTP proxy và đã bảo vệ listener.
Inbound WebSocketAgent → HTTPS/WSS URL của controller, thường 443Egress HTTPS từ agent; proxy/controller nhận WebSocketAgent chỉ được ra HTTPS hoặc controller ở sau reverse proxy.
SSH-launchedController → SSH daemon trên agentLuồng ngược lại, controller egress đến agentController được phép quản trị host qua SSH.

50000 không phải port bắt buộc của mọi Jenkins agent. Chỉ mở nó khi thật sự chọn inbound TCP và controller đang listen trên port đó. Không mở 50000 để sửa một WebSocket agent offline; nó không dùng listener này.

WebSocket không phải TCP được bọc lại

WebSocket bắt đầu bằng HTTPS rồi HTTP/1.1 Upgrade thành một kết nối WebSocket dài. Agent chạy với -webSocket và gọi URL base của controller; reverse proxy chuyển WebSocket tới HTTP endpoint của Jenkins. Không chuyển port TCP 50000 vào một location HTTP của Nginx và cũng không kỳ vọng header Upgrade làm TCP listener hoạt động.

WebSocket thường giảm số port cần expose tại edge, nhưng mọi hop vẫn phải hỗ trợ Upgrade và idle timeout dài: load balancer, WAF, CDN, ingress và reverse proxy. Nếu một hop đóng socket sau 60 giây, agent sẽ reconnect dù Jenkins controller hoàn toàn khỏe.

Chuẩn bị controller node và mạng

Tạo node tại Manage Jenkins → Nodes → New Node, chọn permanent node rồi launch method inbound/WebSocket theo lựa chọn hiện trên controller. Đặt tên ổn định, remote root riêng, labels mô tả capability và trust tier, số executor thận trọng, và service account không có quyền administrator mặc định. Xem chi tiết scheduling ở Labels và executors và cách dùng label trong Pipeline agents.

Không nhận build trên built-in node/controller trong production. Đặt executor của controller là 0, sau đó route job sang pool đúng capability. Điều này giảm blast radius khi mã build hoặc plugin có vấn đề, nhưng không thay thế hardening controller.

Giả định phiên bản và plugin

Mẫu trên trang này giả định:

  • Jenkins LTS, Java trên controller và Java chạy agent.jar nằm trong ma trận hỗ trợ hiện tại. Đối chiếu Java Support Policy trước khi nâng cấp.
  • agent.jar được tải từ chính controller đang phục vụ môi trường đó, không lấy bản tùy ý từ mirror hay image cũ. Remoting đi kèm controller cần tương thích với controller.
  • Launch method WebSocket xuất hiện trên UI của controller và được tổ chức cho phép. Khả năng này phụ thuộc Jenkins core/Remoting và cấu hình Global Security của version đang chạy; xác nhận bằng node lab thay vì suy luận từ tài liệu của version khác.
  • Plugin không tự nhiên cần cho inbound agent Java cơ bản. Pipeline cần plugin Pipeline phù hợp; wrapper/service manager, cloud provisioner hoặc launcher bổ sung là dependency riêng phải được pin, cập nhật và review.

Không copy nguyên lệnh của một agent cũ sau khi controller nâng LTS hoặc thay proxy. Vào trang node, lấy lệnh hiện hành, đối chiếu URL, -name, transport và version Java. Nền tảng Java, disk, DNS và network cần thiết được tổng hợp tại Yêu cầu hệ thống.

Firewall DNS proxy và context path

Trước khi khởi động service, lập bảng luồng thực tế thay vì mở rộng firewall để “thử”.

Thành phầnInbound TCPWebSocket qua proxyKiểm tra tối thiểu
Agent firewallCho phép outbound đến controller TCP port đã chọnCho phép outbound TCP 443 đến hostname proxyDNS resolve hostname canonical và chỉ thấy luồng cần thiết.
Edge firewallCho phép subnet/VPN agent vào TCP listenerCho phép HTTPS đến proxy theo policyKhông public upstream controller chỉ để debug.
Controller firewallNhận TCP listener nếu dùng TCPChỉ nhận từ proxy/private network khi proxy terminate TLSAllowlist proxy hoặc subnet rõ ràng.
Reverse proxyKhông áp dụng cho TCP listener thông thườngChuyển HTTP/1.1 Upgrade, giữ socket idle đủ lâu101 Switching Protocols và log upgrade thành công.

Controller URL, reverse proxy và agent phải dùng một URL canonical. Nếu Jenkins được public tại https://jenkins.example.invalid/jenkins/, agent phải dùng cả hostname, HTTPS và context path /jenkins/; không dùng URL upstream như http://127.0.0.1:8080/ từ một host khác. Proxy phải giữ prefix và forwarded headers nhất quán. Xem Jenkins sau Reverse Proxy và TLS trước khi dùng WebSocket qua proxy.

Agent secret identity và blast radius

Agent secret là giá trị xác thực của một inbound node identity. Nó cho phép process chứng minh với controller rằng nó được phép kết nối như node đó. Secret không phải API token của người dùng, không phải private key SSH và không nên được dùng lại cho một node khác.

Nếu lộ secret, người có nó có thể cố kết nối giả làm node tương ứng. Blast radius tùy policy controller nhưng phải được đánh giá ít nhất theo labels, executor, workspace, account OS, network egress và dữ liệu còn trên node đó. Kẻ tấn công không mặc nhiên thành Jenkins administrator, nhưng một agent được controller tin cậy là một điểm chạy mã mạnh; xử lý sự cố như một compromise của identity và host scope, không chỉ là lỗi login.

Secret khác credential ID

Agent secret và credentials ID có mục đích khác nhau:

Khái niệmDùng choCó thể xuất hiện ở đâuKhông được suy ra
Agent secretXác thực agent.jar là một inbound nodeSecret delivery, file permission giới hạn hoặc secret managerKhông phải credentialsId của Pipeline và không cấp quyền deploy.
Credentials IDTham chiếu đến credential Jenkins như release-api-tokenJenkinsfile hoặc cấu hình job, ví dụ credentialsId: 'release-api-token'ID không phải giá trị credential; không dùng làm agent secret.

Pipeline chỉ nên tham chiếu credential ID theo phạm vi folder/job hẹp nhất, rồi nạp secret trong stage tin cậy ngắn nhất. Agent secret không được đặt vào Jenkinsfile, withCredentials, build parameter, artifact hay shared library. Xem Credentials trong Pipeline để phân biệt binding Pipeline với identity kết nối agent.

Lấy lệnh từ controller mà không tạo shell history

Sau khi tạo node, mở trang node và chọn Launch agent. Controller hiển thị chính xác URL, tên node, transport và agent secret cho identity đó. Đây là nguồn lệnh đáng tin cậy cho controller hiện tại, nhưng màn hình này không phải lý do để paste secret vào terminal, chat, ticket hoặc repository.

Quy trình an toàn là:

  1. Người được phép mở trang node và xác nhận hostname/controller URL trước khi lấy lệnh.
  2. Gửi secret trực tiếp vào kênh provision đã được phê duyệt, như secret manager, automation có audit, hoặc file đã mã hóa do service account đọc được. Không copy qua shell interactive.
  3. Tạo service config chỉ chứa URL, node name, -webSocket, work directory và đường dẫn secret. Ví dụ bên dưới dùng -secret @/etc/jenkins-agent/secret, không chứa giá trị secret.
  4. Đặt quyền file chỉ cho account service; kiểm tra bằng test -s hoặc ACL, không bằng cat, echo, printenv hay screenshot.

-secret @<file> yêu cầu agent.jar của controller hiểu file reference. Xác nhận lệnh controller hiển thị hoặc java -jar agent.jar -help trên bản agent đã tải trước khi chuẩn hóa mẫu này. Nếu version chỉ cung cấp secret dạng argument, dùng cơ chế secret injection của service manager theo policy tổ chức; không viết java ... -secret <giá-trị-thật> vào shell history. Xóa history sau khi lộ secret không thu hồi được bản sao trong terminal log, audit hay process list.

Secret không được phép xuất hiện trong log hoặc Git

Không commit secret, private key, agent.env, service unit có secret, ảnh chụp Launch agent, Console Output, support bundle hay ticket. Cũng không chạy set -x, printenv hoặc diagnostic dump trong process có secret. Masking log không thay thế việc không in secret.

Rotation và phản ứng khi nghi ngờ lộ lọt

Có owner, mục đích và ngày review cho mỗi node identity. Rotation không chỉ là thay một file: drain node, thay identity/secret theo UI và version controller, cập nhật secret delivery, restart một agent lab/canary, rồi thu hồi giá trị cũ. Một số version/quy trình có thể yêu cầu tạo lại inbound node identity để nhận secret mới; xác nhận hành vi trên Jenkins LTS của bạn, không giả định có nút rotate giống nhau ở mọi version.

Khi nghi ngờ lộ secret hoặc host bị compromise:

  1. Đặt node tạm offline để ngăn allocation mới; giữ bằng chứng log theo incident process.
  2. Dừng service agent theo cách có kiểm soát, đánh giá build đang chạy, workspace, process, network egress và credential từng được đưa vào host.
  3. Replace hoặc recreate identity để secret cũ không còn hợp lệ; provision secret mới qua kênh bảo mật.
  4. Rotate credential deploy, token registry hoặc key khác từng có mặt trên host nếu assessment cho thấy có thể bị đọc. Không chỉ đổi agent secret rồi coi incident đã xong.
  5. Rebuild hoặc re-attest host/image nếu trust của OS không còn đáng tin, rồi chạy canary trên pool cô lập trước khi đưa node online.

Cấu hình WebSocket sau reverse proxy

Một WebSocket agent dùng URL HTTPS của Jenkins và cờ -webSocket. Mẫu lệnh chỉ dùng placeholder, không phải lệnh để paste secret thật:

java -jar /opt/jenkins/agent.jar \
  -url 'https://jenkins.example.invalid/jenkins/' \
  -secret '@/etc/jenkins-agent/secret' \
  -name 'lab-inbound-ws-01' \
  -webSocket \
  -workDir '/var/lib/jenkins-agent'

Dấu @ bảo agent đọc secret từ file thay vì đưa secret vào source code của command. URL có trailing slash và context path giống Jenkins URL. Không thay bằng http://controller:8080 để né certificate hoặc proxy; cách đó thay đổi route, trust boundary và có thể bỏ qua policy edge.

TLS và certificate trust

Java cần tin certificate chain mà proxy trình bày cho hostname trong URL. Với CA công khai, trust store Java/OS đã cập nhật thường đủ; với CA nội bộ, phân phối CA root/intermediate qua image management hoặc trust store do đội vận hành quản lý. Kiểm tra SAN hostname, chain và expiry; không thay verification bằng curl -k, certificate tự ký không tin cậy hoặc một flag bỏ certificate check.

Khi proxy terminate TLS nhưng controller chạy HTTP private ở phía sau, agent chỉ tin certificate của proxy/public hostname. Khi proxy và controller là hai host khác nhau, bảo vệ cả hop nội bộ bằng private network hoặc TLS/mTLS theo threat model. Certificate private key thuộc proxy/secret store, không thuộc agent work directory hoặc repository.

Kiểm tra proxy trước khi khởi động agent

Từ host agent lab, xác minh DNS và TLS với CA cụ thể. Các biến bên dưới không có secret:

CONTROLLER_URL='https://jenkins.example.invalid/jenkins/'
CONTROLLER_CA='/etc/ssl/certs/organization-ca.pem'

curl --fail --silent --show-error --head \
  --cacert "$CONTROLLER_CA" \
  "$CONTROLLER_URL/login"

Kết quả mong đợi là response HTTPS hợp lệ, không redirect tới http://, 127.0.0.1:8080 hoặc URL làm mất /jenkins/. Sau đó kiểm tra cấu hình proxy tại mọi hop: HTTP/1.1 upstream, Upgrade, Connection, TLS headers và idle timeout đủ với socket dài. Cấu hình Nginx và cách kiểm tra 101 được mô tả tại Jenkins sau Reverse Proxy và TLS.

Cài agent như service trên Linux

Ví dụ này dùng một Linux host lab, user service không đăng nhập interactive và systemd. Cài Java theo baseline tương thích Jenkins, không dùng account root để chạy agent. Quy trình cài Jenkins controller trên host Linux nằm ở Cài Jenkins trên Linux; nếu controller lab ở container, xem Chạy Jenkins với Docker.

Tạo thư mục và lấy agent.jar

Provision secret qua kênh ngoài shell trước. Các lệnh dưới đây chỉ tạo thư mục và kiểm tra metadata; chúng không tạo hoặc hiển thị secret.

sudo install -d -o root -g jenkins-agent -m 0750 /etc/jenkins-agent
sudo install -d -o jenkins-agent -g jenkins-agent -m 0750 /var/lib/jenkins-agent
sudo install -d -o root -g root -m 0755 /opt/jenkins

curl --fail --location --proto '=https' --tlsv1.2 \
  --output /tmp/agent.jar \
  'https://jenkins.example.invalid/jenkins/jnlpJars/agent.jar'
sudo install -o root -g root -m 0644 /tmp/agent.jar /opt/jenkins/agent.jar
rm -f /tmp/agent.jar

sudo test -s /etc/jenkins-agent/secret
sudo stat -c '%U:%G %a %n' /etc/jenkins-agent/secret

Kết quả mong đợi: agent.jar đọc được bởi service, work directory ghi được bởi jenkins-agent, và lệnh stat chỉ in owner/group/mode/path của secret file. Ví dụ policy có thể dùng root:jenkins-agent với mode 0640 và thư mục 0750, miễn chỉ service identity được đọc. Không dán secret vào sudo tee, không tạo file placeholder có vẻ giống secret thật, và không đưa file secret vào /var/lib/jenkins-agent hoặc workspace.

Systemd unit có backoff

Lưu unit sau dưới /etc/systemd/system/jenkins-agent.service. Giá trị URL/tên node là placeholder công khai; file secret được provision riêng như phần trước.

[Unit]
Description=Jenkins inbound WebSocket agent (lab)
Wants=network-online.target
After=network-online.target
StartLimitIntervalSec=300
StartLimitBurst=5

[Service]
Type=simple
User=jenkins-agent
Group=jenkins-agent
WorkingDirectory=/var/lib/jenkins-agent
ExecStart=/usr/bin/java -jar /opt/jenkins/agent.jar -url https://jenkins.example.invalid/jenkins/ -secret @/etc/jenkins-agent/secret -name lab-inbound-ws-01 -webSocket -workDir /var/lib/jenkins-agent
Restart=on-failure
RestartSec=15
NoNewPrivileges=true
PrivateTmp=true
ProtectHome=true
ProtectSystem=strict
ReadWritePaths=/var/lib/jenkins-agent

[Install]
WantedBy=multi-user.target

Restart=on-failure cùng RestartSec=15 giúp service hồi phục lỗi tạm thời mà không quay vòng vô hạn. StartLimitBurst=5 trong 300 giây biến reconnect failure kéo dài thành tín hiệu cần điều tra thay vì tạo log storm. Những hardening directive phải được kiểm thử với Java, work directory và toolchain của bạn; nếu buộc phải nới một directive, ghi rõ lý do và chỉ nới đường dẫn cần thiết.

Sau khi review file, enable/start bằng change procedure của lab:

sudo systemctl daemon-reload
sudo systemctl enable --now jenkins-agent.service
sudo systemctl status --no-pager jenkins-agent.service
sudo journalctl -u jenkins-agent.service -n 100 --no-pager

Không dùng systemctl cat hoặc journalctl làm nơi chứa secret. Log tốt chỉ cần cho biết URL đã kết nối, WebSocket/Remoting được thiết lập, node online hoặc mã lỗi; nếu command/log vô tình lộ secret, xử lý như incident và rotate identity.

Cài agent như service trên Windows

Trên Windows, dùng service account riêng không có local administrator, remote desktop hay quyền share không cần thiết. Có thể dùng Windows service wrapper được tổ chức phê duyệt, chẳng hạn WinSW, nhưng wrapper là dependency ngoài Jenkins: pin version, kiểm tra checksum/provenance, review XML và cập nhật như phần mềm vận hành. Không dùng Scheduled Task hay cmd.exe /c chứa một command có secret chỉ để “chạy nền”.

Tạo C:\ProgramData\JenkinsAgent\start-agent.ps1 chỉ chứa placeholder công khai và đường dẫn secret, không chứa secret:

$java = 'C:\Program Files\Eclipse Adoptium\jre\bin\java.exe'
$agentJar = 'C:\ProgramData\JenkinsAgent\agent.jar'
$controllerUrl = 'https://jenkins.example.invalid/jenkins/'
$secretFile = '@C:\ProgramData\JenkinsAgent\secret'
$workDir = 'C:\JenkinsAgent\work'

& $java -jar $agentJar `
  -url $controllerUrl `
  -secret $secretFile `
  -name 'lab-inbound-win-01' `
  -webSocket `
  -workDir $workDir
exit $LASTEXITCODE

Service wrapper gọi powershell.exe -NoProfile -File C:\ProgramData\JenkinsAgent\start-agent.ps1; cấu hình wrapper không cần biết giá trị secret. Secret được secret manager hoặc quy trình privileged ghi trực tiếp vào C:\ProgramData\JenkinsAgent\secret, sau đó ACL chỉ cấp read cho <SERVICE_ACCOUNT> và full control cho Administrators theo policy. Ví dụ kiểm tra ACL không lộ nội dung:

icacls 'C:\ProgramData\JenkinsAgent\secret'
Test-Path -Path 'C:\ProgramData\JenkinsAgent\secret' -PathType Leaf

Cấu hình service restart on failure với delay/backoff ở wrapper, ghi stdout/stderr vào thư mục log có retention, và chuyển sự kiện quan trọng vào Windows Event Log hoặc hệ thống log tập trung. Trước production, kiểm tra service vẫn khởi động sau reboot, certificate CA nội bộ nằm trong Java trust store phù hợp, và user service chỉ ghi được work/log directory. Hướng dẫn chuẩn bị Jenkins trên Windows có tại Cài Jenkins trên Windows.

Vòng đời reconnect logging và shutdown

Trạng thái và reconnect

Vòng đời bình thường là provision node → khởi động agent → Online → nhận allocation → tạm offline để bảo trì → drain → dừng hoặc thay thế. Online chỉ chứng minh channel hiện có; nó không chứng minh toolchain, workspace, disk hay trust tier vẫn đúng. Sau mỗi reconnect, kiểm tra agent log, Java version, labels, work directory, disk và một canary không dùng credential.

Đừng đặt retry vô hạn như biện pháp khắc phục. Reconnect lặp lại là triệu chứng của một trong các lớp: DNS, firewall, proxy idle timeout, TLS/certificate trust, URL/context path, secret/identity, Java process, disk hết hoặc controller quá tải. Backoff hạn chế ảnh hưởng nhưng không thay thế root-cause analysis.

Giám sát và log không nhạy cảm

Quan sát ở cả ba lớp:

  • Controller: trạng thái node Online/offline, node log, queue reason, số executor bận/rảnh, thời điểm disconnect và thay đổi config/plugin.
  • Service agent: systemctl status/journald trên Linux; Service Control Manager, Event Log và wrapper log trên Windows. Theo dõi exit code, restart count, Java process, CPU, RAM, disk/inode và work directory.
  • Network/proxy: DNS failure, TLS handshake, HTTP 101 Switching Protocols, 4xx/5xx, idle timeout và reconnect interval. Không log Authorization header, request body hoặc secret query/argument.

Đặt alert cho agent offline kéo dài, restart burst, tỷ lệ reconnect tăng, queue time tăng theo label, disk gần đầy và certificate sắp hết hạn. Một dashboard chỉ có trạng thái xanh không cho thấy agent đang flap hay queue không có executor phù hợp.

Drain và shutdown an toàn

Để bảo trì hoặc retire node, vào trang node và đánh dấu temporarily offline với lý do ticket/change. Việc này ngăn allocation mới; sau đó quan sát build hiện có. Chờ build an toàn kết thúc hoặc xử lý cancel theo quy trình workload, rồi mới dừng service bằng systemctl stop jenkins-agent.service hoặc Windows Service Control Manager. Không dùng kill -9, tắt máy hay xóa remote root khi agent còn build nếu chưa đánh giá mất artifact, deploy dở dang và Pipeline durability.

Sau khi service dừng, xác nhận node offline trên controller, lưu log cần thiết, dọn workspace theo retention policy và thu hồi secret/identity khi retire. Khởi động lại chỉ sau khi canary chứng minh Java, TLS, Remoting, label và work directory hợp lệ. Với agent production, record owner và thời điểm shutdown để người khác không “bật lại cho hết queue” mà bỏ qua nguyên nhân.

Lab local WebSocket từng bước

Lab này tạo một agent Linux tạm thời chỉ chạy printf, uname và sleep. Không checkout repository, không dùng credential Pipeline, không mở port 50000, không yêu cầu Docker socket và không tác động controller production.

Điều kiện lab

  • Một Jenkins lab đã cài theo Docker hoặc Linux, với Jenkins URL HTTPS canonical. Nếu có reverse proxy/context path, nó đã qua kiểm tra của Reverse Proxy và TLS.
  • Một Linux VM/host disposable có Java tương thích, account jenkins-agent, disk trống và outbound HTTPS tới controller. Host không có access production, credential deploy hay label trusted-release.
  • Một CA file lab được tin cậy bởi Java/curl nếu controller dùng CA nội bộ. Không dùng -k.
  • Quyền tạo node trên Jenkins lab và một kênh provision secret được phê duyệt. Nếu không có kênh này, dừng lab thay vì dán secret vào terminal.

Các bước thực hiện

  1. Trong Manage Jenkins → Nodes, tạo permanent node lab-inbound-ws-01. Đặt remote root /var/lib/jenkins-agent, labels linux lab-inbound, một executor và launch method WebSocket hoặc inbound có WebSocket theo UI của Jenkins LTS. Không đặt label release và không dùng built-in node.

  2. Mở Launch agent, kiểm tra URL có HTTPS và context path chính xác. Chuyển secret trực tiếp tới file /etc/jenkins-agent/secret bằng secret delivery của lab. Chỉ chạy sudo test -s /etc/jenkins-agent/secret; không dùng cat hoặc dán secret trong shell.

  3. Tải agent.jar qua HTTPS từ $CONTROLLER_URL/jnlpJars/agent.jar, dùng CA lab để kiểm tra TLS như Kiểm tra proxy trước khi khởi động agent. Tạo systemd unit theo Systemd unit có backoff, thay URL/node name bằng giá trị lab nhưng giữ -webSocket.

  4. Start service và mở node log. Chờ lab-inbound-ws-01 thành Online. Nếu không online, dừng ở đây để kiểm tra URL, certificate, proxy Upgrade, secret và service log; không mở 50000 như một thử nghiệm.

  5. Tạo Pipeline job lab không liên kết SCM, sau đó chạy Jenkinsfile vô hại sau:

    pipeline {
      agent none
    
      stages {
        stage('Xác nhận inbound WebSocket') {
          agent { label 'linux && lab-inbound' }
          steps {
            sh '''
              printf 'node=%s\\n' "$NODE_NAME"
              printf 'workspace=%s\\n' "$WORKSPACE"
              uname -s
              sleep 45
            '''
          }
        }
      }
    }
  6. Khi build đầu đang sleep 45, trigger build thứ hai. Mở Build Queue, node page và Console Output. Agent lab chỉ có một executor nên build thứ hai phải chờ; nó không được chạy trên controller.

  7. Kết thúc: đánh dấu node temporarily offline, chờ hai build xong, sudo systemctl stop jenkins-agent.service, xác nhận node offline, xóa node lab và hủy host/secret lab theo quy trình. Không tái sử dụng work directory hoặc identity lab cho release.

Kết quả mong đợi

Quan sátKết quả đúngNếu không đúng
TLS tới controllercurl --cacert thành công; URL giữ HTTPS và /jenkins/Kiểm tra DNS, CA chain/SAN, Jenkins URL và proxy context path.
Nodelab-inbound-ws-01 là Online, labels linux lab-inbound, 1 executorĐọc node/service/proxy log; kiểm tra secret file permission và Java.
Build đầuLog in node, workspace và Linux; không có secretKiểm tra label, agent account và Jenkinsfile lab.
Build thứ haiChờ trong queue tới khi build đầu trả executorXác nhận chỉ có một executor và không có node khác cùng labels.
NetworkKhông cần TCP 50000; agent giữ online qua khoảng idle đã chọnKiểm tra proxy HTTP/1.1 Upgrade và timeout ở mọi hop.

Troubleshooting

Dấu hiệuNguyên nhân thường gặpKiểm tra và xử lý an toàn
Node không online, log nói secret/identity bị từ chốiSecret sai, node name sai, identity đã thay hoặc secret file không đọc đượcĐối chiếu lệnh Launch agent với node hiện tại, kiểm tra owner/mode/ACL không in nội dung; replace identity nếu nghi ngờ lộ.
PKIX path building failed hoặc hostname mismatchJava không tin CA, chain thiếu, SAN không khớp URL hoặc certificate hết hạnCài CA qua trust-store management, kiểm tra SAN/chain/expiry; không dùng -k hay bỏ verification.
404, redirect lặp hoặc URL mất /jenkins/Sai controller URL, context path hoặc Jenkins URL/proxy rewrite không nhất quánDùng URL canonical có trailing slash; so khớp --prefix, proxy location và Jenkins URL.
Online rồi offline theo chu kỳProxy/WAF/LB thiếu Upgrade hoặc idle timeout thấp; network flapSo log agent với proxy 101/timeout, kiểm tra HTTP/1.1 Upgrade và timeout mọi hop; giữ backoff trong khi sửa nguyên nhân.
WebSocket lỗi nhưng 50000 đóngNhầm WebSocket với TCP listenerVới WebSocket, kiểm tra HTTPS/proxy; chỉ cấu hình fixed TCP listener và firewall nếu chủ đích chuyển sang inbound TCP.
Service restart stormJava path/permission sai, disk đầy, secret file/URL lỗi hoặc controller không reachableĐọc systemctl status/journald hoặc Windows service log, kiểm tra restart count, disk và DNS; không tăng retry vô hạn.
Node online nhưng job vẫn queueLabel expression không khớp, executor bận, node tạm offline hoặc policy concurrency chặnĐọc lý do Build Queue, xác nhận labels/executor; không đổi sang agent any hoặc bật controller executor.
Có dấu hiệu secret đã lộConsole, artifact, shell history, ticket, process list hoặc host compromiseTạm offline node, dừng/đánh giá host, rotate/replace identity và các credential từng có trên host theo incident process.

Checklist trước khi vận hành

  • Jenkins LTS, Java, Remoting agent.jar, launch method và plugin dependency đã được đối chiếu version/policy; agent.jar lấy từ controller của môi trường.
  • Node có remote root, labels, executor, owner và trust tier rõ ràng; built-in node production có 0 executor.
  • Đã chọn chủ đích WebSocket hoặc inbound TCP. 50000 chỉ được dùng và allowlist khi controller cấu hình TCP listener; WebSocket chỉ cần HTTPS route đã kiểm thử.
  • Firewall direction được review: inbound agent tự mở agent → controller; SSH-launched agent có chiều ngược lại.
  • DNS, Jenkins URL, context path, proxy headers và TLS certificate chain thống nhất; agent Java tin CA thay vì bỏ verification.
  • Mọi proxy/LB/WAF/ingress hỗ trợ WebSocket HTTP/1.1 Upgrade và idle timeout đã được kiểm thử nếu dùng -webSocket.
  • Agent secret được delivery ngoài shell history/Git/log, nằm trong secret manager hoặc file có ACL tối thiểu; secret không bị nhầm với credentials ID.
  • Có owner, review, rotation/replacement và incident playbook cho agent identity; blast radius của host, labels, egress, workspace và credential đã được đánh giá.
  • PR/fork hoặc mã không tin cậy không chạy trên agent tin cậy, không dùng chung workspace/cache/account OS, và không nhận credential release.
  • Linux/Windows service chạy account tối thiểu, có restart backoff, log retention, alert offline/reconnect/disk và smoke test sau reboot/reconnect.
  • Quy trình drain, shutdown, cleanup và retire ngăn allocation mới trước khi dừng service; canary không có credential được chạy trước khi đưa agent trở lại.

Nguồn Jenkins chính thức

Đọc tiếp

On this page