Cách triển khai ứng dụng Node.js bằng Terraform trên Ubuntu 14.04
Một bài báo từ LuồngVới sự trợ giúp của các công cụ điều phối, các chuyên gia DevOps có thể triển khai một ngăn xếp bằng cách tận dụng một vài lệnh gọi API. Terraform là một công cụ rất đơn giản nhưng mạnh mẽ cho phép bạn viết ngăn xếp của bạn dưới dạng mã, sau đó chia sẻ và cập nhật nó bằng cách sử dụng Git để xác nhận các file định nghĩa. Terraform được tạo ra bởi HashiCorp , tác giả của các công cụ nguồn mở phổ biến như Vagrant , Packer và Consul .
Terraform cung cấp một cấu hình chung để chạy cơ sở hạ tầng của bạn, từ các server vật lý và ảo đến các nhà cung cấp dịch vụ email và DNS. Sau khi ra mắt, Terraform thay đổi cơ sở hạ tầng một cách an toàn và hiệu quả khi cấu hình phát triển.
Hướng dẫn này chỉ cho bạn cách cài đặt môi trường cho ứng dụng Node.js đầy đủ chức năng, tinh vi bằng DigitalOcean , Terraform , Cloud-init và PM2 trên Ubuntu 14.04. Là ứng dụng ví dụ của ta , ta sẽ sử dụng Cabin , một ứng dụng React & Redux Node.js open-souce được phát triển bởi GetStream.io . Đầu ra cuối cùng sẽ là một ứng dụng mạng xã hội có nhiều tính năng, có thể mở rộng!
Bạn sẽ bắt đầu bằng cách sử dụng Terraform để triển khai Cabin bằng cấu hình được định nghĩa . Sau đó, bạn sẽ đi sâu vào cấu hình đó để có thể làm quen với cách nó hoạt động.
Nếu bạn chỉ quan tâm đến việc cài đặt Terraform trên server DigitalOcean của bạn , vui lòng xem Cách sử dụng Terraform với DigitalOcean .
Yêu cầu
Để làm theo hướng dẫn này, bạn cần :
- Một server Ubuntu 14.04 dung lượng 2 GB mà bạn sẽ tạo trong hướng dẫn này với Terraform.
- Ứng dụng khách Git được cài đặt trên máy local của bạn.
- Có account Facebook để bạn có thể tạo Ứng dụng Facebook, vì Cabin sử dụng Facebook để đăng nhập.
- Một domain như
cabin.example.com
; bạn sẽ trỏ domain này đến địa chỉ IPv4 mà bạn sẽ nhận được ở Bước 4 và bạn cần domain này cho URL trang web trong Facebook.
Mặc dù không phải là bắt buộc, nhưng hướng dẫn này giả sử bạn đã hoàn thành loạt bài hướng dẫn về Cabin của Stream . Bạn cần các khóa API và cài đặt cho một số nhà cung cấp cần thiết để Cabin hoạt động trong quá trình production , vì chúng đóng một role không thể thiếu trong chức năng của Cabin.
Nếu bạn không lấy được các khóa này, hướng dẫn này sẽ vẫn hoạt động. Bạn vẫn có thể sử dụng Terraform để cung cấp và triển khai ứng dụng Cabin, nhưng ứng dụng sẽ không thể sử dụng được cho đến khi bạn cấu hình tất cả các thành phần bắt buộc của nó.
Để biết thêm thông tin về các dịch vụ này, vui lòng truy cập các bài đăng blog sau từ Stream:
Bước 1 - Lấy ứng dụng mẫu
Sao chép ứng dụng ví dụ Cabin từ GitHub vào một folder bạn chọn trên máy local của bạn. Ta đang sử dụng máy Mac và giả sử bạn cũng vậy.
Đầu tiên, chuyển đến folder chính của bạn.
- cd ~
Sau đó, sử dụng git
để sao chép repository :
- git clone https://github.com/GetStream/stream-react-example.git
Thao tác này sao chép ứng dụng mẫu vào một folder mới có tên là stream-react-example
. Điều hướng đến folder stream-react-example/terraform/do/cabin
có chứa dự án Cabin's Terraform.
- cd stream-react-example/terraform/do/cabin
Ta sẽ làm việc với folder này trong giây lát. Nhưng trước tiên, hãy cài đặt Terraform.
Bước 2 - Cài đặt Terraform
Để cài đặt đơn giản trên OSX, bạn có thể cài đặt Terraform bằng Homebrew bằng cách đưa ra lệnh sau:
- brew install terraform
Ngoài ra, bạn có thể download Terraform từ http://terraform.io . Sau khi bạn download , hãy cung cấp nó cho đường dẫn lệnh của bạn, như được hiển thị bên dưới.
- PATH=location/of/terraform:$PATH
Điều này tạm thời thêm Terraform vào đường dẫn của bạn. Nếu bạn muốn thay đổi này là vĩnh viễn, hãy chỉnh sửa file ~/.bash_profile
trên OSX và thêm dòng này:
export PATH=location/of/terraform:$PATH
Tiếp theo, để kiểm tra xem Terraform đã được cài đặt đúng cách chưa, hãy chạy lệnh sau:
- terraform
Bạn sẽ thấy kết quả sau, hiển thị các tùy chọn của Terraform:
Outputusage: terraform [--version] [--help] <command> [<args>] Available commands are: apply Builds or changes infrastructure destroy Destroy Terraform-managed infrastructure fmt Rewrites config files to canonical format get Download and install modules for the configuration graph Create a visual graph of Terraform resources init Initializes Terraform configuration from a module output Read an output from a state file plan Generate and show an execution plan push Upload this Terraform module to Atlas to run refresh Update local state file against real resources remote Configure remote state storage show Inspect Terraform state or plan taint Manually mark a resource for recreation untaint Manually unmark a resource as tainted validate Validates the Terraform files version Prints the Terraform version
Trước khi Terraform có thể khởi động cơ sở hạ tầng của bạn, ta cần cấu hình hai thứ:
Vì vậy, trước tiên hãy quan tâm đến mã thông báo DigitalOcean.
Bước 2 - Cấu hình Mã thông báo truy cập DigitalOcean
Terraform cần mã thông báo truy cập DigitalOcean của bạn để sử dụng API DigitalOcean.
Đăng nhập vào account DigitalOcean của bạn và nhấp vào liên kết API . Sau đó nhấp vào nút Tạo mã thông báo mới . Đảm bảo kiểm tra Quyền truy cập ghi . Giao diện user sẽ hiển thị một khóa truy cập mới mà bạn nên sao chép vào clipboard của bạn , vì khóa sẽ không hiển thị nếu bạn truy cập lại trang.
Bây giờ, hãy mở file variables.tf
bằng editor yêu thích của bạn và tìm phần token
:
variable "token" { description = "DO Token" }
Thêm một dòng mới bắt đầu bằng text default =
và bao gồm mã thông báo API DigitalOcean của bạn. Hãy nhớ đặt mã thông báo trong dấu ngoặc kép.
variable "token" { description = "DO Token" default = "57eaa5535910eae8e9359c0bed4161c895c2a40284022cbd2240..." }
Lưu và đóng file .
Bây giờ, hãy cấu hình Terraform để sử dụng cặp SSH key của ta .
Bước 3 - Thêm cặp SSH key của bạn
Terraform cần SSH key để kết nối với server của ta sau khi được tạo, vì vậy, Terraform có thể cài đặt các gói và triển khai ứng dụng.
Tìm trong ~/.ssh
của bạn để xem bạn đã có một cặp khóa chưa:
- ls -al ~/.ssh
Rất có thể, bạn có ít nhất một cặp khóa bao gồm private key và public key . Ví dụ: bạn có thể có id_rsa.pub
và id_rsa
.
Cảnh báo : Nếu cặp khóa hiện tại của bạn đã được liên kết với account DigitalOcean của bạn, bạn cần xóa nó bằng cách sử dụng trang tổng quan DigitalOcean hoặc tạo một cặp khóa mới để tránh xung đột.
Nếu bạn không có bất kỳ cặp khóa nào hoặc nếu khóa bạn có đã được liên kết với account DigitalOcean của bạn, thì hãy xem hướng dẫn của DigitalOcean về cài đặt SSH key để cài đặt một khóa .
Bạn cần dán nội dung của file .pub
vào file variables.tf
, giống như bạn đã làm với mã thông báo API. Nếu bạn đang sử dụng máy Mac, bạn có thể sao chép public key SSH của bạn vào clipboard bằng cách ra lệnh sau:
- pbcopy < ~/.ssh/your_key.pub
Bạn cũng có thể hiển thị nội dung của public key ra màn hình bằng lệnh cat
và sao chép nó vào clipboard của bạn theo cách thủ công:
- cat ~/.ssh/your_key.pub
Sau đó, mở file variables.tf
trong editor và thêm nội dung của file public key SSH của bạn vào cài đặt sshkey
:
variable "sshkey" { description = "Public ssh key (for Cabin user)" default = "ssh-rsa AAAAB3NzaC1yc2EAAAADA...== nick@getstream.io" }
Khi bạn đã hoàn thành bước này, hãy lưu và thoát khỏi file .
Nếu bạn đã tạo khóa mới để sử dụng với Terraform và DigitalOcean, bạn cần chạy hai lệnh này để khóa mới của bạn sẽ được sử dụng thay vì khóa mặc định của bạn:
- eval "$(ssh-agent -s)"
- ssh-add ~/.ssh/your_id_rsa
Bạn có thể cần chạy điều này mỗi khi bạn mở một shell mới nếu bạn đang sử dụng cặp khóa thay thế.
Đến đây bạn đã cung cấp cho Terraform các biến cần thiết, bạn đã sẵn sàng để tạo server và triển khai ứng dụng của bạn với Terraform.
Bước 4 - Chạy Terraform
Đến phần thú vị! Hãy xem cơ sở hạ tầng mà ta sẽ xây dựng. Terraform sẽ làm rất nhiều việc cho ta , từ cài đặt server đến triển khai ứng dụng của ta . Ta có thể yêu cầu Terraform chỉ cho ta chính xác những gì nó sẽ làm với lệnh sau:
- terraform plan
Đầu ra của lệnh này khá dài dòng, vì vậy hãy cố gắng tập trung vào các câu lệnh sau:
Output+ digitalocean_server.cabin-web ... + digitalocean_floating_ip.cabin-web-ip ... + digitalocean_ssh_key.cabin-ssh-key ... + template_file.pm2_processes_conf ... + template_file.userdata_web ...
Biểu tượng “+” ở đầu dòng nghĩa là tài nguyên sẽ được tạo. Các tài nguyên có tiền tố là digitalocean
là các tài nguyên sẽ được tạo trên DigitalOcean. Trong trường hợp cụ thể này, Terraform sẽ tạo Server, một IP nổi và sẽ thêm SSH key của ta .
Cảnh báo Ta không chịu trách nhiệm về các khoản phí có thể tích lũy trong khi (các) bản sao của bạn hoặc các dịch vụ của bên thứ ba trực tuyến. Biểu mẫu lệnh được terraform apply
sẽ tạo Server với 2GB RAM (~ $ 0,03 / giờ) và một IP nổi mà DigitalOcean cung cấp miễn phí. Để biết con số chính xác, hãy kiểm tra kỹ giá cập nhật trên trang web của DigitalOcean.
Bây giờ đã đến lúc chạy Terraform và quay lên Cabin trên Server.
- terraform apply
Sau một thời gian ngắn, bạn sẽ thấy Terraform in ra như sau:
OutputApply complete! Resources: 6 added, 0 changed, 0 destroyed. The state of your infrastructure has been saved to the path below. This state is required to modify and destroy your infrastructure, so keep it safe. To inspect the complete state use the `terraform show` command. State path: terraform.tfstate Expected output: web_ipv4 = 111.111.111.111
web_ipv4
là địa chỉ IP nổi mà bạn có thể sử dụng để truy cập vào Server.
Đăng nhập vào Server mới được tạo bằng giá trị bạn thấy cho web_ipv4
:
- ssh cabin@your_value_for_web_ipv4
Bạn cũng có thể sử dụng lệnh
- terraform output web_ipv4
để hiển thị địa chỉ IP được liên kết với giá trị đó nếu bạn bỏ lỡ.
Bạn sẽ thấy thông báo chào mừng này khi đăng nhập:
_____ _ _ / ____| | | (_) | | __ _| |__ _ _ __ | | / _` | '_ \| | '_ \ | |___| (_| | |_) | | | | | \_____\__,_|_.__/|_|_| |_| Initializing Cabin. Please wait... (up 1 minute) | CTRL+C to interrupt
Bạn có thể cần đợi vài phút để DigitalOcean cung cấp version và cloud-init
để cài đặt các gói cần thiết cho Cabin. Nhưng khi nó đã sẵn sàng, bạn sẽ thấy điều này:
Cabin initialized! Check running processes... ┌──────────┬────┬──────┬───────┬────────┬─────────┬────────┬─────────────┬──────────┐ │ App name │ id │ mode │ pid │ status │ restart │ uptime │ memory │ watching │ ├──────────┼────┼──────┼───────┼────────┼─────────┼────────┼─────────────┼──────────┤ │ api │ 0 │ fork │ 14105 │ online │ 0 │ 36s │ 75.898 MB │ enabled │ │ app │ 1 │ fork │ 14112 │ online │ 0 │ 36s │ 34.301 MB │ enabled │ │ www │ 2 │ fork │ 14119 │ online │ 0 │ 36s │ 50.414 MB │ enabled │ └──────────┴────┴──────┴───────┴────────┴─────────┴────────┴─────────────┴──────────┘ Use `pm2 show <id|name>` to get more details about an app
Sau khi Cabin bắt đầu và chạy, hãy trỏ trình duyệt trên điện thoại di động của bạn tới http:// your_value_for_web_ipv4
. Cabin đang hoạt động và bạn sẽ thấy màn hình tải. Nhưng đó là chừng mực ta sẽ nhận được cho đến khi ta thực hiện một số thay đổi đối với mã trên server .
Bước 5 - (Tùy chọn) Cấu hình Cabin
Ứng dụng Cabin đã được triển khai, nhưng nó vẫn chưa thể sử dụng được. Ta phải cấu hình Facebook và một số dịch vụ khác nếu ta muốn Cabin hoạt động đầy đủ.
Trước tiên, bạn cần tạo một ứng dụng Facebook bằng domain hợp lệ, như cabin.example.com
được ánh xạ tới địa chỉ web_ipv4
được tạo trong quá trình cài đặt. Thêm bản ghi vào DNS của bạn hoặc thêm mục nhập vào file /etc/hosts
của bạn ánh xạ domain của bạn với địa chỉ IP.
Để tạo ứng dụng Facebook, hãy làm theo các bước sau:
- Truy cập https://developers.facebook.com/docs/apps/register#step-by-step-guide .
- Đăng nhập vào Facebook.
- Trong Ứng dụng của tôi, nhấp vào Thêm ứng dụng mới .
- Nhập tên cho ứng dụng của bạn (ví dụ:
Cabin - My Example App
). - Nhập Email liên hệ của bạn.
- Đối với Danh mục , sử dụng menu thả xuống để chọn danh mục cho ứng dụng. Trong trường hợp của ta , đó là Phong cách sống .
- Nhấp vào nút Tạo ID ứng dụng .
- Nếu được yêu cầu, hãy hoàn thành captcha.
- Sao chép
appId
. Nó sẽ là một giá trị số được tìm thấy ở đầu màn hình. Bạn cần nó ngay thôi. - Chọn Trang tổng quan từ thanh bên trái.
- Dưới tiêu đề Bắt đầu với Facebook SDK , hãy nhấp vào Chọn một nền tảng .
- Chọn Web cho nền tảng.
- Tìm trường URL của trang web và nhập
http://cabin.example.com
. - Nhấp vào Tiếp theo .
Nếu bạn gặp sự cố, bạn có thể làm theo hướng dẫn từng bước này . Nếu bạn gặp khó khăn, có một bài viết tuyệt vời về cách gỡ lỗi cài đặt ứng dụng của bạn trên Facebook, bạn có thể tìm thấy tại đây .
Sau khi có appID
của bạn , bạn cần thay thế cài đặt appID
mặc định trên server .
Vì vậy, hãy đảm bảo bạn đã đăng nhập vào server của bạn . Nếu không, hãy đăng nhập lại bằng:
- ssh cabin@your_value_for_web_ipv4
Sau khi đăng nhập, hãy mở file ~/stream-react-example/app/views/index.ejs
:
- nano ~/stream-react-example/app/views/index.ejs
Thay đổi appId
mặc định bằng appId
do Facebook cung cấp.
FB.init({ appId : 'your_facebook_app_id', xfbml : true, version : 'v2.6', status : true, cookie : true, })
Lưu file này và đóng nó.
Tiếp theo, bạn cần biết password database cho Cabin, được tạo bởi Terraform khi tạo server . Để nhận giá trị này, hãy nhập lệnh sau:
- grep DB_PASSWORD processes.yml
Sao chép password này; bạn cần nó trong thời gian ngắn.
Tệp env.sh
là nơi bạn sẽ nhập thông tin đăng nhập của bạn cho các nhà cung cấp và dịch vụ khác nhau mà Cabin phụ thuộc vào. Tệp này đặt các thông tin xác thực này vào các biến môi trường, sau đó ứng dụng sẽ đọc được. Đây là một biện pháp phòng ngừa bảo mật, vì nó giữ cho password và khóa thoát khỏi Git.
Mở env.sh
:
- nano env.sh
Bạn sẽ thấy nội dung sau:
Outputexport NODE_ENV=production export JWT_SECRET=ABC123 export DB_USERNAME=cabin export DB_HOST=localhost export DB_PASSWORD=VALUE export DB_PORT=3306 export MAPBOX_ACCESS_TOKEN=ADD_VALUE_HERE export S3_KEY=ADD_VALUE_HERE export S3_SECRET=ADD_VALUE_HERE export S3_BUCKET=ADD_VALUE_HERE export STREAM_APP_ID=ADD_VALUE_HERE export STREAM_KEY=ADD_VALUE_HERE export STREAM_SECRET=ADD_VALUE_HERE export ALGOLIA_APP_ID=ADD_VALUE_HERE export ALGOLIA_SEARCH_ONLY_KEY=ADD_VALUE_HERE export ALGOLIA_API_KEY=ADD_VALUE_HERE export KEEN_PROJECT_ID=ADD_VALUE_HERE export KEEN_WRITE_KEY=ADD_VALUE_HERE export KEEN_READ_KEY=ADD_VALUE_HERE export IMGIX_BASE_URL=https://react-example-app.imgix.net/uploads export API_URL=http://localhost:8000
Như bạn thấy , file này xuất ra một loạt các biến môi trường chứa thông tin về các dịch vụ khác nhau mà Cabin cần. Để Cabin hoạt động trong quá trình production , bạn cần phải điền vào tất cả các giá trị này.
Dưới đây là bảng phân tích nhanh về các cài đặt này:
- NODE_ENV : Môi trường mà Node.js sẽ chạy trong. (Sản xuất sẽ cung cấp cải tiến tốc độ).
- JWT_SECRET : Bí mật xác thực để xác thực Mã thông báo web JSON giữa giao diện API và Web (ứng dụng).
- DB_USERNAME : Tên user cho database .
- DB_HOST : Tên server database .
- DB_PASSWORD: Mật khẩu của database mà bạn vừa xem bằng cách nhìn vào
processes.yml
. - DB_PORT : Cổng database (cổng mặc định 3306 cho MySQL).
- MAPBOX_ACCESS_TOKEN : Mã thông báo truy cập cho MapBox (để lập bản đồ vị trí ảnh).
- S3_KEY : Khóa Amazon S3 để lưu trữ hình ảnh.
- S3_SECRET : Amazon S3 bí mật để lưu trữ hình ảnh.
- S3_BUCKET : Bộ chứa S3 của Amazon để lưu trữ hình ảnh. Đảm bảo rằng group này tồn tại.
- STREAM APP ID: Suối ID ứng dụng. Đảm bảo rằng tất cả các group nguồn cấp dữ liệu bắt buộc đều tồn tại trong ứng dụng được liên kết với ID này.
- STREAM_KEY : Khóa API stream .
- STREAM_SECRET : Tính năng bí mật của ứng dụng phát trực tuyến.
- ALGOLIA_APP_ID : Id ứng dụng Algolia dành cho tìm kiếm.
- ALGOLIA_SEARCH_ONLY_KEY : Phím chỉ tìm kiếm Algolia để tìm kiếm.
- ALGOLIA_API_KEY : Khóa API Algolia để tìm kiếm.
- KEEN_PROJECT_ID : Keen theo dõi id dự án (cho số liệu thống kê).
- KEEN_WRITE_KEY : Khóa ghi phím theo dõi (cho số liệu thống kê).
- KEEN_READ_KEY : Chỉnh khóa đọc theo dõi (để biết số liệu thống kê).
- IMGIX_BASE_URL : URL cơ sở Imgix (để hiển thị ảnh ở các kích thước cụ thể).
- API_URL : URL được ứng dụng này sử dụng cho API của nó. Bạn cần thay đổi điều này từ
localhost
thành domain trỏ đến địa chỉ IP của bạn, chẳng hạn nhưcabin.example.com
.
Để biết thêm chi tiết về các dịch vụ và biến môi trường được tham chiếu, hãy truy cập các bài đăng trên blog sau và đảm bảo bạn đã cấu hình từng ứng dụng như được chỉ định:
Khi bạn đã cấu hình tất cả các nhà cung cấp, hãy nhập password cho database của bạn và các giá trị cho các nhà cung cấp trong file env.sh
Thoát và lưu file env.sh
Sau đó, nguồn file , tải các giá trị vào các giá trị môi trường mà Cabin sẽ sử dụng:
- source ./env.sh
Tiếp theo, bạn cần chạy lệnh webpack
. Webpack là một công cụ xây dựng JavaScript quản lý mã giao diện user cho Cabin. Webpack sẽ tạo lại các file JavaScript và CSS dựa trên các giá trị được đặt bởi file env.sh
mà bạn vừa thay đổi. Vì vậy, hãy thay đổi thành folder app
:
- cd app
Và sau đó chạy lệnh webpack
để xây dựng lại các file JavaScript giao diện user . Điều này sẽ đưa một số mã thông báo của nhà cung cấp vào mã giao diện user .
- webpack --progress --color
Bạn sẽ thấy kết quả sau:
OutputHash: 64dcb6ef9b46a0243a8c Version: webpack 1.13.1 Time: 21130ms Asset Size Chunks Chunk Names ./public/js/app.js 2.22 MB 0 [emitted] app ./public/css/styles.css 23 kB 0 [emitted] app [0] multi app 28 bytes {0} [built] + 685 hidden modules Child extract-text-webpack-plugin: + 2 hidden modules Child extract-text-webpack-plugin: + 2 hidden modules
Với các cài đặt đã có, hãy chạy PM2 để reload tất cả các quy trình ứng dụng đảm bảo rằng tất cả các thành phần đều sử dụng cài đặt mới:
- pm2 restart all
Output[PM2] Applying action restartProcessId on app [all](ids: 0,1,2) [PM2] [api](0) ✓ [PM2] [app](1) ✓ [PM2] [www](2) ✓ ┌──────────┬────┬──────┬───────┬────────┬─────────┬────────┬─────────────┬──────────┐ │ App name │ id │ mode │ pid │ status │ restart │ uptime │ memory │ watching │ ├──────────┼────┼──────┼───────┼────────┼─────────┼────────┼─────────────┼──────────┤ │ api │ 0 │ fork │ 30834 │ online │ 516 │ 0s │ 39.027 MB │ enabled │ │ app │ 1 │ fork │ 30859 │ online │ 9 │ 0s │ 22.504 MB │ enabled │ │ www │ 2 │ fork │ 30880 │ online │ 9 │ 0s │ 19.746 MB │ enabled │ └──────────┴────┴──────┴───────┴────────┴─────────┴────────┴─────────────┴──────────┘
Đó là nó! Đến đây bạn có thể đăng xuất khỏi server từ xa của bạn .
- exit
Cuối cùng, hãy truy cập lại http:// your_value_for_web_ipv4
trong trình duyệt của bạn để xem trang web. Thao tác này sẽ hiển thị ảnh bìa với liên kết đăng nhập Facebook. Sau khi đăng nhập, bạn có thể khám phá ứng dụng sau này.
PM2 quản lý các quy trình cho Cabin và nó có thể là một công cụ tuyệt vời giúp bạn gỡ lỗi các vấn đề. Bạn có thể sử dụng pm2 list
để xem trạng thái của các thành phần của ứng dụng và pm2 logs
để xem stream log cho ứng dụng, điều này có thể giúp bạn chẩn đoán bất kỳ lỗi cấu hình nào.
Bây giờ ta hãy tìm hiểu cấu hình Terraform đã giúp cho việc triển khai này trở nên khả thi.
Bước 6 - Khám phá các ô cấu hình
Vì vậy, làm thế nào để tất cả điều này hoạt động? Hãy xem các file trong repository lưu trữ mà ta đã nhân bản vào máy local của bạn . Mặc dù không có gì để bạn sửa đổi trong phần này, bạn vẫn nên làm theo trên máy của riêng mình để có thể cảm nhận được cách các phần ăn trùng với nhau.
Dự án Terraform được chia thành nhiều file và folder để giữ cho ứng dụng sạch sẽ và dễ hiểu. Ta đã đặt tất cả các file DigitalOcean của bạn bên trong folder terraform/do
của repository , có cấu trúc sau:
do └── cabin ├── files │ ├── cabin-web-nginx.conf │ └── cabin_mysql_init.sh ├── main.tf ├── outputs.tf ├── templates │ ├── processes.tpl │ └── web.tpl └── variables.tf
Hãy xem các file ở trên, bắt đầu với main.tf
Mở nó trong editor yêu thích của bạn.
Điều đầu tiên ta làm là cho Terraform biết nhà cung cấp cloud nào ta sẽ sử dụng.
provider "DigitalOcean" { token = "${var.token}" }
Việc xác định nhà cung cấp DigitalOcean chỉ đơn giản như vậy. Bạn có thể tìm thấy danh sách đầy đủ các nhà cung cấp được hỗ trợ trong tài liệu Terraform .
Cấu hình biến
Terraform cho phép bạn xác định các biến, nghĩa là bạn có thể đặt giá trị mặc định cho việc triển khai của bạn . Bằng cách đó, bạn sẽ không phải nhập chi tiết mỗi lần hoặc các giá trị mã cứng trong suốt cấu hình của bạn . Hãy xem cách đặt các biến để triển khai trên DigitalOcean.
Hãy xem qua variables.tf
, vị trí mà ta đã xác định các biến cần thiết để chạy ứng dụng Cabin.
variable "token" { description = "DO Token" } variable "region" { description = "DO Region" }
Để giúp bạn hiểu rõ hơn về cách các biến được xử lý bên trong Terraform, ta hãy xem qua ví dụ trên.
Đối với biến vùng, ta đã chỉ định một giá trị mặc định. Nếu bạn không chỉ định một giá trị mặc định, Terraform sẽ nhắc bạn một giá trị, như thể hiện trong ví dụ sau:
Outputterraform plan var.token DO Token Enter a value:
Bạn cũng có thể cung cấp các biến khi bạn chạy terraform apply
. Ví dụ: nếu bạn muốn chỉ định một vùng khác, bạn có thể chạy Terraform với đối số var
:
- terraform -var 'region=ams3' apply
Điều này overrides mọi cài đặt đã cấu hình .
Cài đặt server
Trong main.tf
ta yêu cầu Terraform cung cấp Server trên DigitalOcean. Theo mặc định, ta triển khai một server có các đặc điểm sau:
resource "digitalocean_server" "cabin-web" { image = "ubuntu-14-04-x64" name = "cabin-web" region = "${var.region}" size = "2gb" ssh_keys = [ "${digitalocean_ssh_key.cabin-ssh-key.id}" ] user_data = "${template_file.userdata_web.rendered}" }
Ta đang tạo DigitalOcean Server mới với 2GB RAM được gọi là cabin-web và sử dụng hình ảnh ubuntu-14-04-x64 . Bằng cách nhìn vào định nghĩa tài nguyên ở trên, bạn có thể thấy rằng rất dễ dàng để thay đổi hình ảnh và kích thước của server .
Dữ liệu user & Cloud-Init
Được rồi, vậy user-data
chính xác là gì? Đây là cách dễ nhất để gửi các lệnh và hướng dẫn đến một version cloud tại thời điểm khởi động. Cùng với cloud-init
, nó trở thành một cách mạnh mẽ để cấu hình version của bạn mà không cần sử dụng các ứng dụng bên thứ ba không cần thiết như Chef hoặc Puppet .
Chương trình cloud-init
được nhúng trong nhiều bản phân phối Linux. Nó có một bộ hướng dẫn nhỏ cho phép bạn thực hiện các việc đơn giản như thêm user , quản lý group , tạo file và chạy các tập lệnh hoặc lệnh shell với quyền root.
Hãy đi sâu vào thuộc tính user_data
để bạn hiểu rõ hơn về thuộc tính này:
resource "digitalocean_server" "cabin-web" { ... user_data = "${template_file.userdata_web.rendered}" }
Mục tiêu của ta là bắt đầu một Server mới với Cabin được cài đặt và chạy, đồng thời có cloud-init
xử lý công việc nặng nhọc cho ta . Trường user_data
trỏ đến file mẫu, sử dụng một biến trỏ đến một khai báo khác trong main.tf
:
resource "template_file" "userdata_web" { template = "${file("${path.module}/templates/web.tpl")}" vars { userdata_sshkey = "${var.sshkey}" userdata_nginx_conf = "${base64encode(file("${path.module}/files/cabin-web-nginx.conf"))}" userdata_mysql_init = "${base64encode(file("${path.module}/files/cabin_mysql_init.sh"))}" userdata_pm2_conf = "${base64encode("${template_file.pm2_processes_conf.rendered}")}" userdata_env = "${base64encode("${template_file.env.rendered}")}" userdata_motd = "${base64encode(file("${path.module}/files/motd"))}" userdata_motd_script = "${base64encode(file("${path.module}/files/motd.sh"))}" userdata_giturl = "${var.git_url}" userdata_index = "${base64encode(file("${path.module}/files/index.html"))}" } }
Terraform cung cấp các chức năng cho phép bạn chuyển đổi văn bản. Ta có thể sử dụng tính năng này để đưa các giá trị vào các mẫu bằng cách đọc các file và sau đó chuyển đổi nội dung thành các chuỗi được mã hóa Base64 để chúng có thể được chuyển qua các lệnh gọi API.
Phần cụ thể này chuẩn bị dữ liệu cho các mẫu templates/web.tpl
chứa tất cả các cài đặt và lệnh để thực thi trên server .
Hãy xem qua file web.tpl
và xem nó hoạt động như thế nào.
Phần đầu tiên cài đặt user ban đầu và vô hiệu hóa quyền truy cập root:
#cloud-config users: - name: cabin groups: sudo sudo: ['ALL=(ALL) NOPASSWD:ALL'] shell: /bin/bash home: /home/cabin lock_passwd: true ssh-authorized-keys: - ${userdata_sshkey} disable_root: true
Câu lệnh đầu tiên trong web.tpl
phải là #cloud-config
. Nếu bạn quên thêm điều này, cloud-init
sẽ không nhận cấu hình và các lệnh đã cho sẽ không được thực thi trên version đích.
Các lệnh trong phần này thực hiện như sau:
- thêm user
cabin
vào hệ thống với một khoản trợ cấp để trở thành user siêu cấp -
lock-passwd: true
từ chối xác thực password , vì vậy usercabin
cần sử dụng xác thực SSH key để truy cập server . -
ssh-authorized-keys
cài đặt ssh-key của user vào file ủy quyền -
disable_root: true
được sử dụng để vô hiệu hóa quyền truy cập SSH với quyền là user root
Lưu ý ${userdata_sshkey}
là một biến được đặt khi ta gọi mẫu trong main.tf
Tiếp theo, ta cài đặt MySQL, Nginx, Git và các gói khác mà ta cần cho ứng dụng của bạn :
package_update: true packages: - mysql-server-5.6 - libmysqlclient-dev - iptables-persistent - git - nginx - npm - pwgen
Cách dễ nhất để cài đặt các gói với cloud-init
là tận dụng module Gói để cài đặt danh sách các gói nhất định. Mô-đun này sử dụng trình quản lý gói mặc định cho bản phân phối. Vì ta đang sử dụng Ubuntu, quá trình này sẽ cài đặt các gói có apt
.
Tiếp theo, ta ghi một số file vào hệ thống file , sử dụng dữ liệu ta đã chuyển vào mẫu làm nội dung file :
write_files: - encoding: b64 content: ${userdata_nginx_conf} path: /tmp/cabin-web.conf - encoding: b64 content: ${userdata_pm2_conf} path: /tmp/processes.yml - encoding: b64 content: ${userdata_mysql_init} path: /tmp/cabin_mysql_init.sh permissions: '0554'
Phần này sử dụng module write_file
để tạo file . Trong ví dụ trên, ta đang tạo các file sau:
-
cabin-web.conf
chứa cấu hình NGINX. -
processes.yml
sử dụng bởi PM2 để xử lý các quá trình Node.js. -
cabin_mysql_init.sh
là một tập lệnh tùy chỉnh được sử dụng để khởi tạo database MySQL.
Lưu ý khi ta chuyển dữ liệu vào mẫu, ta đã mã hóa nó thành Base64. Ta chỉ định mã hóa khi ta ghi file để nội dung có thể được giải mã.
Trong phần tiếp theo, ta sử dụng module runcmd
để chạy một số lệnh shell để tạo các luật firewall bằng iptables
:
runcmd: - iptables -A INPUT -i lo -j ACCEPT - iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT - iptables -A INPUT -p tcp --dport ssh -j ACCEPT - iptables -A INPUT -p tcp --dport 80 -j ACCEPT - iptables -A INPUT -p tcp --dport 8000 -j ACCEPT - iptables -A INPUT -p tcp --dport 3000 -j ACCEPT - iptables -A INPUT -j DROP - iptables -A OUTPUT -j ACCEPT - invoke-rc.d iptables-persistent save …
Sau đó, mã sử dụng iptables-persistent
để cung cấp cấu hình firewall trong trường hợp version khởi động lại.
Sau khi các luật firewall được áp dụng, các lệnh còn lại để cài đặt và khởi động Cabin được thực thi:
- apt-get update --fix-missing - curl -sL https://deb.nodesource.com/setup_5.x | bash && apt-get install -y nodejs - npm install pm2 webpack -g - cd /home/cabin && sudo -u cabin git clone ${userdata_giturl} - mv /tmp/env.sh /home/cabin/stream-react-example/env.sh - cd /home/cabin/stream-react-example/api && sudo -u cabin npm install - cd /home/cabin/stream-react-example/app && sudo -u cabin npm install - cd /home/cabin/stream-react-example/www && sudo -u cabin npm install - chown cabin.cabin /home/cabin/stream-react-example/env.sh && /home/cabin/stream-react-example/env.sh - mv /tmp/processes.yml /home/cabin/stream-react-example/processes.yml - chown cabin.cabin /home/cabin/stream-react-example/processes.yml - /tmp/cabin_mysql_init.sh - cd /home/cabin/stream-react-example && sudo -u cabin pm2 start processes.yml - mv /tmp/cabin-web.conf /etc/nginx/sites-available/cabin-web - rm /etc/nginx/sites-enabled/default - ln -s /etc/nginx/sites-available/cabin-web /etc/nginx/sites-enabled - service nginx reload
Tất cả các lệnh này đều được thực thi với quyền root và chỉ xảy ra ở lần khởi động đầu tiên . Nếu bạn khởi động lại máy, runcmd
sẽ không được thực thi nữa.
Đến đây bạn đã tìm hiểu thêm về Terraform, hãy khám phá cách xử lý vòng đời cơ sở hạ tầng của bạn.
Bước 7 - Quản lý vòng đời của ngăn xếp
Terraform giúp bạn có thể lưu trạng thái của ngăn xếp, cập nhật ngăn xếp, xóa nó và áp dụng các thay đổi mã.
Bạn có thể nhận thấy rằng sau khi bạn chạy terraform apply
, một file có tên là terraform.tfstate
được tạo trong folder cabin
.
Tệp này rất quan trọng vì nó chứa các tham chiếu đến các tài nguyên thực tế được tạo trên DigitalOcean. Về cơ bản, file này cho Terraform biết số nhận dạng của các tài nguyên mà nó quản lý.
Nếu bạn chạy lại terraform apply
, Terraform sẽ không bắt đầu lại và xóa sạch mọi thứ bạn đã tạo. Thay vào đó, nó sẽ chỉ làm những phần nó chưa hoàn thành. Vì vậy, nếu quy trình của bạn không thành công giữa chừng do sự cố mạng hoặc sự cố API, bạn có thể giải quyết vấn đề và chạy lại lệnh. Terraform sẽ bắt đầu từ nơi nó dừng lại.
Thay đổi cấu hình server
Bạn cũng có thể sử dụng terraform apply
để thay đổi cấu hình của Server. Ví dụ: nếu bạn cần thay đổi trung tâm dữ liệu hoặc khu vực hoặc tăng bộ nhớ mà Server sử dụng để có thêm lưu lượng truy cập, Terraform sẽ làm cho cả hai tác vụ trở nên cực kỳ dễ dàng.
Bạn có thể điều chỉnh vùng Server bằng cách chạy lệnh terraform apply
và overrides các biến region
và server_size
. Điều này cho phép Terraform biết rằng Server hiện có cần được phá hủy và Server mới cần được cung cấp để đáp ứng các yêu cầu.
Cảnh báo : Terraform sẽ làm thùng rác Server hiện có . Giả sử rằng bạn đang chạy database MySQL của bạn trên cùng một server với ứng dụng của bạn, điều này cũng sẽ làm dữ liệu MySQL của bạn trở nên thùng rác. . Để tránh điều này, ta khuyên bạn nên thực hiện xuất database trước bước này hoặc tốt hơn là chạy database MySQL của bạn trên một Server chuyên dụng .
Nếu bạn muốn thay đổi vùng hoặc trung tâm dữ liệu chứa Server của bạn , hãy thực hiện lệnh sau:
- terraform apply -var "region=sfo2"
Và, khi cơ sở user của bạn phát triển, bạn có thể cần thay đổi kích thước Server để phù hợp với lưu lượng truy cập bổ sung. Bạn có thể làm điều đó với biến server_size
như sau:
- terraform apply -var "server_size=4gb"
Server sẽ bị xóa và thay thế bằng một cái mới, đồng thời ứng dụng sẽ được triển khai lại và cấu hình .
Phá hủy ngăn xếp
Một trong những điều tuyệt vời về Terraform là nó xử lý toàn bộ vòng đời của ngăn xếp. Bạn có thể dễ dàng phá hủy những gì bạn đã xây dựng bằng cách chạy một lệnh Terraform đơn giản (phá hủy).
- terraform destroy
Terraform sau đó sẽ nhắc bạn xác nhận bạn thực sự muốn phá hủy tất cả tài nguyên:
OutputDo you really want to destroy? Terraform will delete all your managed infrastructure. There is no undo. Only 'yes' will be accepted to confirm. Enter a value: yes
Khi Terraform hoàn tất, kết quả cuối cùng sẽ giống như sau:
Outputdigitalocean_server.cabin-web: Destroying... digitalocean_server.cabin-web: Still destroying... (10s elapsed) digitalocean_server.cabin-web: Destruction complete digitalocean_ssh_key.cabin-ssh-key: Destroying... template_file.userdata_web: Destroying... template_file.userdata_web: Destruction complete template_file.pm2_processes_conf: Destroying... template_file.pm2_processes_conf: Destruction complete digitalocean_ssh_key.cabin-ssh-key: Destruction complete Apply complete! Resources: 0 added, 0 changed, 5 destroyed.
Như bạn thấy , tất cả các tài nguyên đã bị phá hủy.
Triển khai các version mã mới
Trong trường hợp bạn áp dụng các thay đổi đối với cơ sở mã của bạn , bạn cần tải các thay đổi lên server mà không có thời gian chết hoặc ít. Ta đã cài đặt PM2 trên server của bạn và nó sẽ xử lý công việc nặng nhọc cho ta .
PM2 lắng nghe các thay đổi hệ thống file trong ứng dụng. Để chạy version mã mới hơn, chỉ cần SSH vào Server và đưa ra git pull
trong folder chứa ứng dụng. Thao tác này sẽ hướng dẫn server lấy từ repository của bạn. Khi các file thay đổi, PMZ sẽ tự động khởi động lại quá trình Node.
Ví dụ: nếu có một version Cabin mới và bạn muốn triển khai version mã mới nhất cho server , bạn sẽ đăng nhập vào server của bạn :
ssh cabin@your_value_for_web_ipv4
Sau đó, trên server , chuyển đến folder chứa ứng dụng Cabin:
- cd ~/stream-react-example
Và cuối cùng là kéo version mới nhất xuống.
- git pull
Sau khi có mã mới, ứng dụng của bạn sẽ tự động khởi động lại và khách truy cập sẽ thấy version mới nhất. Nếu vì lý do nào đó mà PM2 không nắm bắt được thay đổi, hãy khởi động lại mọi thứ theo cách thủ công với
- pm2 restart all
và tất cả các thành phần sẽ khởi động lại.
Kết luận
Sử dụng DigitalOcean, Terraform, Cloud-init và PM2, bạn đã cài đặt thành công môi trường production cho Cabin.
Khi sử dụng Terraform, tất cả cơ sở hạ tầng của bạn được lưu trữ dưới dạng mã. Điều này giúp group của bạn dễ dàng theo dõi các thay đổi và cộng tác. Nó cũng cho phép bạn áp dụng các thay đổi cơ sở hạ tầng lớn một cách tương đối dễ dàng.
Các tin liên quan
Cách thiết lập vsftpd cho Tải xuống ẩn danh trên Ubuntu 16.042016-08-25
Cách cấu hình Cụm Galera với MariaDB 10.1 trên server Ubuntu 16.04
2016-08-19
Cách tạo Mảng RAID với mdadm trên Ubuntu 16.04
2016-08-16
Cách quản lý mảng RAID với mdadm trên Ubuntu 16.04
2016-08-16
Cách thiết lập NFS Mount trên Ubuntu 16.04
2016-08-04
Cách cài đặt và sử dụng Byobu để quản lý thiết bị đầu cuối trên Ubuntu 16.04
2016-08-04
Cách cài đặt và cấu hình Ansible trên Ubuntu 16.04
2016-07-22
Cách cài đặt và cấu hình Sphinx trên Ubuntu 16.04
2016-07-22
Cách triển khai ứng dụng Node.js và MongoDB với Rancher trên Ubuntu 14.04
2016-07-18
Cách cài đặt và sử dụng BaasBox trên Ubuntu 14.04
2016-07-13