Bootleg: Deploy ứng dụng Elixir không còn là cơn ác mộng
Bootleg giúp bạn build, deploy và quản lý Elixir releases chỉ với vài lệnh mix. Đơn giản, extensible, và không cần viết script bash lằng nhằng.
Nguyễn Nhật Long
@nguyennhatlong1303
Nếu bạn đã từng deploy một ứng dụng Elixir lên production, bạn biết cái cảm giác đó ngồi viết shell script, SSH vào từng server, copy file release, restart service, rồi cầu trời nó không crash. Mình đã trải qua giai đoạn đó và thật sự không muốn lặp lại.
Bootleg ra đời để giải quyết đúng cái pain point này. Đây là một Elixir library cho phép bạn build và deploy ứng dụng Elixir/Phoenix theo cách có cấu trúc, reproducible, và quan trọng nhất viết config bằng Elixir luôn chứ không phải YAML hay TOML gì cả.
Tại sao không dùng Ansible, Capistrano hay mấy cái kia?
Mình cũng đã thử. Ansible thì okay nhưng bạn phải học thêm một layer YAML nữa, và khi cần customize logic phức tạp thì nó khá cồng kềnh. Capistrano thì gắn chặt với Ruby ecosystem. Còn viết tay shell script thì... mình không muốn nhắc lại.
Cái hay của Bootleg là nó nằm ngay trong Elixir project của bạn, config bằng Elixir DSL, và tích hợp trực tiếp với Distillery để build release. Không cần học thêm tool nào ngoài hệ sinh thái bạn đang dùng.
Setup từ đầu đến khi chạy được
Đầu tiên, thêm dependencies vào mix.exs:
1def deps do2 [3 {:distillery, "~> 2.1.0", runtime: false},4 {:bootleg, "~> 0.13.0", runtime: false}5 ]6end
Cả hai đều có runtime: false vì đây là dev/deploy tooling, không cần chạy trong production app.
Sau đó init Distillery trước:
1mix distillery.init
Lệnh này tạo ra thư mục rel/ với config cơ bản. Nếu bạn chưa dùng Distillery bao giờ thì đây là bước quan trọng Bootleg phụ thuộc vào Distillery để tạo release artifact.
Tiếp theo init Bootleg:
1mix bootleg.init
Nó sẽ tạo ra config/deploy.exs và config/deploy/production.exs. Đây là hai file config chính bạn cần quan tâm.
Cấu trúc config phần quan trọng nhất
config/deploy.exs là nơi bạn define build server tức là server dùng để compile và tạo release:
1use Bootleg.DSL23role :build, "build.example.com",4 workspace: "/home/deploy/build",5 user: "deploy",6 identity: "~/.ssh/id_rsa",7 silently_accept_hosts: true
Còn config/deploy/production.exs define app servers nơi release sẽ được copy đến và chạy:
1use Bootleg.DSL23role :app, ["app1.example.com", "app2.example.com"],4 workspace: "/opt/myapp",5 user: "deploy",6 identity: "~/.ssh/id_rsa",7 silently_accept_hosts: true
Mình thấy cái này hay ở chỗ bạn có thể define nhiều server trong role :app cùng một lúc Bootleg sẽ deploy song song lên tất cả. Không cần viết loop hay gì cả.
Build, deploy, và mọi thứ còn lại
Sau khi config xong, workflow hàng ngày của bạn sẽ trông như thế này:
1# Build release trên build server2mix bootleg.build34# Copy release xuống app servers và chuẩn bị5mix bootleg.deploy67# Start application8mix bootleg.start
Hoặc nếu cần restart:
1mix bootleg.stop2mix bootleg.start34# Hoặc gộp lại5mix bootleg.restart
Và cái mình hay dùng nhất khi có sự cố:
1mix bootleg.rollback
Rollback là tính năng mình đánh giá cao. Bootleg giữ lại các release cũ trên server, nên khi deploy mới bị lỗi, một lệnh là bạn quay về version trước. Không cần SSH vào tay, không cần panic.
Các deployment strategy Bootleg hỗ trợ
Theo kinh nghiệm của mình, setup remote build server riêng là cách tốt nhất cho production. Lý do là build Elixir release cần đúng OS và architecture với production server nếu bạn build trên Mac rồi deploy lên Linux thì sẽ gặp vấn đề với native dependencies. Build server riêng đảm bảo môi trường nhất quán.
| Strategy | Mô tả | Khi nào dùng |
|---|---|---|
| Remote build + Remote deploy | Build trên build server riêng, deploy lên app servers | Production với team lớn |
| Local build + Remote deploy | Build trên máy dev, push lên server | Solo dev hoặc project nhỏ |
| Remote build + Local deploy | Ít phổ biến hơn | Một số edge case đặc biệt |
Customize với Bootleg DSL
Đây là phần mà Bootleg thực sự tỏa sáng so với các tool khác. Bạn có thể hook vào các lifecycle events và chạy custom logic:
1use Bootleg.DSL23# Chạy migration sau khi deploy4after_deploy do5 remote :app do6 "bin/myapp rpc 'MyApp.Release.migrate()'"7 end8end910# Notify Slack sau khi start thành công11after_start do12 IO.puts "Deploy thành công! Version: #{version()}"13end
Bạn có thể dùng remote/2 để chạy lệnh trực tiếp trên server từ trong Elixir code. Mình thấy cái này cực kỳ mạnh bạn có thể viết bất kỳ logic nào bằng Elixir, không bị giới hạn bởi YAML hay template engine.
Ngoài ra còn có các hooks khác:
1before_build do ... end2after_build do ... end3before_deploy do ... end4after_deploy do ... end5before_start do ... end6after_start do ... end
Một số lưu ý thực tế khi dùng
Anh em lưu ý mấy điểm này để tránh mất thời gian debug:
SSH key setup: Bootleg dùng SSHKit.ex bên dưới để connect. Đảm bảo SSH key bạn chỉ định trong identity đã được add vào authorized_keys trên cả build server lẫn app servers. Nghe đơn giản nhưng mình đã thấy nhiều người quên bước này.
Elixir version phải match: Build server và app server cần cùng Elixir/OTP version. Nếu khác nhau, release có thể không chạy được. Dùng asdf hoặc Docker để đảm bảo consistency.
Workspace permissions: User bạn dùng để deploy cần có write permission vào workspace directory. Nếu dùng /opt/myapp thì nhớ chown cho đúng.
silently_accept_hosts: true: Trong môi trường CI/CD, bạn cần option này để không bị prompt xác nhận SSH fingerprint. Trong production thực tế thì nên manage known_hosts properly.
So sánh nhanh với một số alternative
Nếu bạn đang dùng Elixir và self-host infrastructure, Bootleg là lựa chọn tự nhiên nhất. Không phải vì nó perfect, mà vì nó nằm trong cùng ecosystem và bạn không cần context switch sang tool khác.
| Tool | Language | Elixir-native | Extensibility | Learning curve |
|---|---|---|---|---|
| Bootleg | Elixir | ✅ | Cao (Elixir DSL) | Thấp với Elixir devs |
| Ansible | YAML/Python | ❌ | Cao (modules) | Trung bình |
| Capistrano | Ruby | ❌ | Cao | Trung bình |
| Shell scripts | Bash | ❌ | Thấp | Thấp nhưng dễ sai |
| Gigalixir CLI | Elixir | ✅ | Thấp (platform lock-in) | Rất thấp |
Tích hợp vào CI/CD pipeline
Bootleg hoạt động rất tốt trong CI pipeline. Ví dụ với GitHub Actions:
1- name: Deploy to production2 run: |3 mix bootleg.build4 mix bootleg.deploy5 mix bootleg.start6 env:7 MIX_ENV: prod
Bạn cần đảm bảo SSH private key được inject vào CI environment (dùng secrets) và agent forwarding được setup đúng. Mình thường dùng ssh-agent action để handle phần này.
Tình trạng hiện tại của project
Một điều mình cần nói thẳng: Bootleg hiện có ~400 stars trên GitHub và không còn được update thường xuyên. Repo vẫn còn mở nhưng activity khá thấp. Nếu bạn cần một tool đang được maintain tích cực, đây là điều cần cân nhắc.
Tuy nhiên, với những project đang dùng Distillery và cần một deployment workflow đơn giản, Bootleg vẫn hoàn toàn làm được việc. Codebase khá nhỏ gọn và nếu cần fix gì bạn có thể fork và tự patch.
Cộng đồng Elixir hiện cũng có các hướng khác như dùng Fly.io hoặc Render để tránh hẳn việc manage deployment infrastructure. Nhưng nếu bạn cần self-hosted và muốn control hoàn toàn, Bootleg vẫn là một lựa chọn đáng xem xét.
Cho những ai muốn explore thêm, Bootleg có channel #bootleg trên Elixir Slack cộng đồng ở đó khá friendly và responsive với câu hỏi kỹ thuật.
Nguyễn Nhật Long
@nguyennhatlong1303Nguyễn Nhật Long is a Senior Frontend Engineer and Frontend Team Leader with 7 years of experience building real-time fintech platforms. Specializing in React, Next.js, TypeScript, and React Native, shipping 10+ products across Web, Mobile, Telegram Mini-Apps, and Web3.
Thấy hay? Chia sẻ cho bạn bè!