Bước đầu triển khai Continuous Deployment với Travis CI

Một đặc thù của cấu hình Continous Deployment (CD) cho dự án phần mềm đó là thường phải cấu hình để CI slave có khả năng truy xuất tới môi trường deploy, đây là một trong những thách thức đầu tiên khi triển khai CD.

Bài viết này mô tả một cách để vượt qua thách thức này. CI slave được sử dụng là Travis CI – một CI slaver được sử dụng phổ biến đặc biệt là với các dự án mã nguồn mở, hay các dự án mà có repository được host bởi GitHub. Travis CI sẽ truy xuất tới máy chủ deploy thông qua giao thức SSH.

Bạn cần có một chút kiến thức chuyên môn và kinh nghiệm về CI, Docker, SSH và kỹ thuật xác thực khóa để có thể phân tích trọn vẹn bài viết này.

Khai báo stage

Cấu hình bắt đầu bằng thao tác khai báo một stage mới. Thường thì chỉ có các commit trên một số nhánh đặc thù mới được deploy, nên hãy cấu hình cho cả điều này nữa:

  - stage: deploy
    branches:
      only:
      - master

Chuẩn bị các tiền đề để SSH

Các tiền đề này bao gồm:

  1. Đảm bảo sự tồn tại của SSH Agent
  2. Cài đặt private key cho SSH Agent
  3. Khai báo public key của máy chủ deploy cho SSH Agent

Đảm bảo sự tồn tại của SSH Agent

Thao tác này nhằm đảm bảo SSH Agent có tồn tại, và hoạt động, trên runtime của CI slave.

  - stage: deploy
    branches:
      only:
      - master
    before_script:
      - which ssh-agent || ( apt update -y && apt install -y openssh-client )
      - eval $(ssh-agent -s)

Cài đặt private key cho SSH Agent

Mấu chốt của thao tác này là thực thi câu lệnh ssh-add $private-key. Vấn đề nảy sinh khi chúng ta không muốn và sẽ không bao giờ đưa private key vào repository. Giải pháp ở đây tựu trung như sau:

  1. Tạo mới một cặp private/public key
  2. Mã hoá private key và đưa tập tin mã hoá vào repository
  3. Bổ sung key giải mã vào biến môi trường cho runtime
  4. Cấu hình để runtime giải mã private key và thực thi ssh-add
Tạo mới cặp private/public key

Lý do tạo mới là bởi không nên dùng chung cặp key này, đề phòng các trường hợp rò rỉ. Tạo private/public key rất đơn giản, chỉ cần sử dụng command line ssh-keygen. Lưu ý rằng CI runtime không phải là một interactive tty, nên chúng ta cần bỏ trống passphrase.

Mã hóa private key và đưa tập tin mã hóa vào repository

Travis có cung cấp một công cụ cho phép thực hiện được cả hai công việc này đó là Travis CLI. Tôi không muốn cài đặt công cụ này trực tiếp nên sẽ sử dụng thông qua docker container:

docker run --rm -it -v $PWD:/app -w /app ruby bash

Sau khi đăng nhập vào container:

ssh-keygen -f $file_name # Tạo cặp private/public key
gem install travis # Cài đặt travis cli
travis login --com # Điền username/mật khẩu GitHub để đăng nhập http://travis-ci.com
travis encrypt-file $file_name --add --com # Mã hóa private key, khóa giải mã sẽ được đặt vào project tại travis.com
exit # Thoát khỏi container

Kết quả của việc mã hóa là một file $file_name.enc được tạo ra (nếu giải mã file này sẽ được private key), tập tin này cần được bổ sung vào repository. Bước tiếp theo sẽ là tại môi trường deploy khai báo public key vào tập tin ~/.ssh/authorized_keys, sau đó thì có thể xóa private/public key đi.

Giải mã private key và cài đặt cho SSH Agent

Kiểm tra setting tại https://travis.com để xác nhận rằng thông tin khóa giải mã đã được bổ sung vào biến môi trường:

Tại bước mã hóa, travis cli cũng sẽ gợi ý một command line sử dụng OpenSSL để giải mã file .enc, bổ sung command line đó và .travis.yml. Kết quả của command line này là private key ban đầu, file này đã sẵn sàng để sử dụng cho ssh-add.

  - stage: deploy
    branches:
      only:
      - master
    before_script:
      - which ssh-agent || ( apt update -y && apt install -y openssh-client )
      - eval $(ssh-agent -s)
      - openssl aes-256-cbc -K $encrypted_e6cc0fb2b8da_key -iv $encrypted_e6cc0fb2b8da_iv -in $file_name.enc -out private_key -d
      - chmod 600 private_key
      - ssh-add private_key

Cài đặt public key của máy chủ deploy cho SSH Agent

Khi kết nối SSH tới một máy chủ lần đầu tiên, SSH Agent sẽ yêu cầu sự đồng ý từ người dùng. SSH từ travis runtime thì luôn luôn là lần đầu tiên, tuy nhiên tyy tại travis runtime lại không phải là tty tương tác do đó không thể thực hiện thao tác xác nhận được. Thường thì vấn đề này sẽ được giải quyết bằng cách cấu hình để SSH Agent bỏ qua bước yêu cầu xác nhận, tuy nhiên ở đây tôi sẽ sử dụng giải pháp có mức bảo mật nghiêm ngặt hơn đó là khai báo public key của máy chủ deploy.

Việc này được thực hiện bằng các bước như sau:

  1. Lấy public key của máy chủ deploy
  2. Mã hóa public key, đưa tập tin mã hóa vào repository
  3. Đưa khóa giải mã vào biến môi trường tại travis runtime
  4. Cấu hình để runtime giải mã public key và bổ sung vào ~/.ssh/known_hosts
Lấy public key của máy chủ deploy

Public key của các máy chủ được lưu giữ trong file known_hosts. Không dễ để tìm ra public key của máy chủ deploy trong số này. Cách đơn giản nhất là:

  1. Thực hiện SSH tới máy chủ deploy bằng một máy tính bất kỳ, sau đó exit
  2. Chạy command ssh-keygen -F $deploy_server > public_key để ghi public key vào file public_key.

Nội dung của file public_key được tạo ra sẽ tương tự như sau, dòng comment đầu tiền cần phải bỏ đi trước khi thực hiện các bước tiếp theo.

# Host ***.***.***.*** found: line ** 
***.***.***.*** ecdsa-sha2-nistp256***/***+***/***+***=
Mã hóa public key và đưa tập tin mã hóa vào repository

Bước này hoàn toàn tương tự như thao tác mã hóa private key:

  1. Sử dụng travis cli để mã hóa, khóa giải mã sẽ được cập nhật vào biến môi trường cho travis runtime
  2. Bổ sung public key đã mã hóa vào repostitory
  3. Xóa bỏ tập tin public_key
Cấu hình để travis runtime bổ sung public key vào known_hosts

Command dùng để giải mã public key sẽ được travis cli cung cấp. Bổ sung public key vào ~/.ssh/known_hosts có thể thực hiện đơn giản bằng linux stream:

  - stage: deploy
    branches:
      only:
      - master
    before_script:
      // ...
      - openssl aes-256-cbc -K $encrypted_***_key -iv $encrypted_** -in $public_key.enc -out production_public_key -d
      - cat production_public_key >> ~/.ssh/known_hosts

Sau bước này thì SSH Agent đã sẵn sàng để thực hiện kết nối tới máy chủ deploy mà không cần bất kỳ tương tác người dùng nào.

Truy cập máy chủ deploy và thực thi deployment scripts

Thao tác này đơn giản là thực thi deployment scripts từ xa thông qua giao thức SSH:

  - stage: deploy
    branches:
      only:
      - master
    before_script:
      // ...
    script:
      - ssh $PRODUCTION_USER@$PRODUCTION_SERVER "/bin/bash -s " < production_deploy.sh

Deployment script nên càng đơn giản càng tốt, làm được thế thì chứng tỏ môi trường deploy đủ khỏe mạnh. Chẳng hạn như sau:

#!/bin/sh

cd $DEPLOYMENT_DIR || exit
git pull
docker run ...

_

Leave a Comment

Your email address will not be published. Required fields are marked *