Thứ sáu, 26/05/2017 | 00:00 GMT+7

Cách cài đặt Concourse CI trên Ubuntu 16.04

Concourse CI là một hệ thống tích hợp liên tục hiện đại, có thể mở rộng được thiết kế để tự động hóa các đường ống thử nghiệm với cú pháp khai báo, có thể tổng hợp. Dựa trên thành công của các hệ thống CI trước đó, Concourse nhằm mục đích đơn giản hóa việc quản lý đường ống và loại bỏ các server "bông tuyết" để server thử nghiệm được quản lý tốt như mã mà nó xử lý.

Trong hướng dẫn này, ta sẽ trình bày cách cài đặt Concourse CI trên server Ubuntu 16.04. Ta sẽ cấu hình database PostgreSQL để sử dụng làm phần backend , download và cài đặt các file binary Concourse, sau đó cấu hình các quy trình web và công nhân cho phép ta xây dựng và thực thi các đường ống tích hợp liên tục.

Yêu cầu

Để hoàn thành hướng dẫn này, bạn cần một server Ubuntu 16.04 với ít nhất 1 GB RAM . Cấu hình user sudo không phải root và firewall như được mô tả trong hướng dẫn cài đặt server ban đầu Ubuntu 16.04 trước khi tiếp tục.

Cài đặt và cấu hình PostgreSQL

Trước khi ta download các file binary Concourse CI, ta nên cài đặt một version PostgreSQL trên server của bạn . Concourse sẽ sử dụng database PostgreSQL để lưu trữ dữ liệu đường ống của nó.

Đầu tiên, cập nhật index gói local để làm mới chế độ xem local của các file có sẵn. Sau đó, cài đặt gói postgresqlpostgresql-contrib từ repository mặc định của Ubuntu:

  • sudo apt-get update
  • sudo apt-get install postgresql postgresql-contrib

Sau khi phần mềm database được cài đặt, ta sẽ tạo một user PostgreSQL chuyên dụng có tên là concourse để quản lý các tài sản Concourse trong hệ thống database . Để tạo user này, ta sẽ sử dụng sudo để hoạt động như user hệ thống postgres , có quyền truy cập quản trị vào hệ thống database :

  • sudo -u postgres createuser concourse

Theo mặc định, Concourse cố gắng kết nối với database có tên là atc . Concourse gọi trung tâm API và web chính của nó là “ATC”, viết tắt của “kiểm soát không lưu”. Ta có thể tạo database này và gán quyền sở hữu cho user database concourse chờ để cung cấp quyền truy cập thích hợp:

  • sudo -u postgres createdb --owner=concourse atc

Với database của ta tại chỗ, ta hiện đã sẵn sàng download và cài đặt các file binary Concourse CI.

Download và cài đặt Concourse CI Executables

Concourse cung cấp liên kết đến các file thực thi được biên dịch cho nền tảng Linux trên cả trang web của họ và GitHub.

Nơi dễ nhất để tìm chúng là trên trang download Concourse CI . Trong phần Download , dưới phần Concourse Binaries, nhấp chuột phải và sao chép các vị trí liên kết cho nền tảng tải Linux. Hãy mở trang này, vì ta sẽ quay lại trang này trong giây lát.

Trên server của bạn, hãy chuyển sang /tmp và sau đó sử dụng curl để download liên kết bạn đã sao chép:

  • cd /tmp
  • curl -LO copied_URL_for_concourse_binary

Tiếp theo, ta sẽ download ứng dụng client dòng lệnh fly mới nhất. Trở lại trang download Concourse CI , trong phần Download , bên dưới phần Fly Binaries , nhấp chuột phải và sao chép vị trí liên kết để download nền tảng Linux .

Trên server của bạn, hãy reload liên kết đã sao chép vào /tmp với curl :

  • cd /tmp
  • curl -LO copied_URL_for_fly_binary

Nếu yêu cầu download dẫn đến lỗi, các file sẽ chứa thông báo lỗi HTTP thay vì chương trình binary . Kiểm tra xem các file có thực sự là file thực thi binary hay không bằng lệnh :

  • file *linux_amd64 | grep executable
Output
concourse_linux_amd64: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=3f24eae5da950594d8d1aaea7631bc20883afba3, not stripped fly_linux_amd64: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped

Kết quả kết quả ở trên cho biết các file là file thực thi. Ta có thể thêm quyền thực thi vào các file , xóa hậu tố _linux_amd64 và di chuyển chúng vào folder /usr/local/bin bằng lệnh :

  • chmod +x concourse* fly*
  • sudo mv concourse* /usr/local/bin/concourse
  • sudo mv fly* /usr/local/bin/fly

Yêu cầu version của mỗi chương trình sẽ được coi là một kiểm tra nhỏ đảm bảo mọi thứ đang hoạt động chính xác:

  • cd ~
  • concourse --version
  • fly --version
Output
3.0.1 3.0.1

Bây giờ các mã binary của ta đã sẵn sàng, ta có thể bắt đầu cấu hình Concourse.

Tạo nội dung cấu hình CI của hội nghị

Tiếp theo, ta có thể bắt đầu tập hợp cấu hình và các khóa mà Concourse sẽ sử dụng để khởi động.

Trước khi ta bắt đầu, hãy tạo một folder cấu hình nơi ta có thể giữ tất cả các file có liên quan:

  • sudo mkdir /etc/concourse

Bây giờ ta có thể tạo khóa mã hóa và tạo file xác cấu hình Phòng chờ của ta .

Tạo các file chính

Hội nghị bao gồm một vài thành phần liên quan mà tất cả đều cần có khả năng giao tiếp an toàn với nhau.

ATC là trung tâm chính xử lý các yêu cầu web và API và điều phối các đường ống. Công nhân quản lý các container để chạy các việc CI / CD được xác định trong đường ống. TSA là một server SSH tùy chỉnh đăng ký an toàn các nhân viên với ATC.

Mặc dù ta sẽ chạy tất cả các thành phần này trên một server duy nhất, nhưng worker và TSA mong muốn giao tiếp an toàn. Để đáp ứng mong đợi này, ta sẽ tạo ba bộ khóa:

  • một cặp khóa cho thành phần TSA
  • một cặp key cho công nhân
  • một cặp khóa ký phiên được sử dụng để ký mã thông báo cho các phiên user và giao tiếp TSA với ATC

Vì chúng sẽ được sử dụng tự động khi mỗi thành phần khởi động, ta cần tạo các khóa này mà không cần password . Ta có thể tạo từng cặp khóa này trong folder /etc/concourse bằng lệnh :

  • sudo ssh-keygen -t rsa -q -N '' -f /etc/concourse/tsa_host_key
  • sudo ssh-keygen -t rsa -q -N '' -f /etc/concourse/worker_key
  • sudo ssh-keygen -t rsa -q -N '' -f /etc/concourse/session_signing_key

Nếu ta kiểm tra trong folder hội nghị, ta có thể thấy rằng ba public key và ba private key hiện có sẵn:

  • ls -l /etc/concourse
Output
total 24 -rw------- 1 root root 1679 May 11 17:19 session_signing_key -rw-r--r-- 1 root root 394 May 11 17:19 session_signing_key.pub -rw------- 1 root root 1679 May 11 17:19 tsa_host_key -rw-r--r-- 1 root root 394 May 11 17:19 tsa_host_key.pub -rw------- 1 root root 1675 May 11 17:19 worker_key -rw-r--r-- 1 root root 394 May 11 17:19 worker_key.pub

TSA sẽ quyết định công nhân nào được phép kết nối với hệ thống bằng cách kiểm tra file khóa được ủy quyền. Ta cần điền trước file khóa được ủy quyền bằng public key của worker mà ta đã tạo để nó có thể kết nối thành công.

Vì đây là nhân viên duy nhất của ta , ta chỉ có thể sao chép file qua:

  • sudo cp /etc/concourse/worker_key.pub /etc/concourse/authorized_worker_keys

Bây giờ ta đã có các file chính và file ban đầu cho nhân viên được ủy quyền, ta có thể tạo các file sẽ xác cấu hình Phòng chờ của ta .

Tạo file cấu hình môi trường

Hệ binary Concourse không tự nhiên đọc từ file cấu hình. Tuy nhiên, nó có thể nhận các giá trị cấu hình từ các biến môi trường được truyền vào khi quá trình bắt đầu.

Trong giây lát, ta sẽ tạo các file đơn vị systemd để xác định và quản lý các dịch vụ Concourse của ta . Các file đơn vị có thể đọc các biến môi trường từ một file và chuyển chúng vào quá trình khi nó bắt đầu. Ta sẽ tạo một file xác định các biến cho quy trình web Concourse, các biến này khởi động các thành phần ATC và TSA và một file khác cho quy trình Concourse worker .

Tạo và mở file cho quy trình web bằng lệnh :

  • sudo nano /etc/concourse/web_environment

Bên trong, ta sẽ xác định các biến môi trường cần thiết bởi các thành phần ATC và TSA. Mỗi biến bắt đầu bằng CONCOURSE_ .

Để bắt đầu, ta sẽ xác định một số giá trị tĩnh mà ta không cần sửa đổi. Các biến này sẽ xác định vị trí của khóa phiên và TSA riêng tư, file xác định công nhân được ủy quyền và vị trí socket PostgreSQL:

/ etc / concourse / web_enosystem
# These values can be used as-is CONCOURSE_SESSION_SIGNING_KEY=/etc/concourse/session_signing_key CONCOURSE_TSA_HOST_KEY=/etc/concourse/tsa_host_key CONCOURSE_TSA_AUTHORIZED_KEYS=/etc/concourse/authorized_worker_keys CONCOURSE_POSTGRES_SOCKET=/var/run/postgresql 

Tiếp theo, ta sẽ đặt một số biến cần thay đổi để phù hợp với môi trường của bạn. CONCOURSE_EXTERNAL_URL xác định địa chỉ IP và cổng mà dịch vụ sẽ liên kết. Đặt giá trị này thành địa chỉ IP công cộng của server và cổng 8080.

Ta cũng sẽ đặt tên user và password cho group main , có chức năng như group quản trị Phòng chờ. Bạn có thể chọn bất kỳ tên user và password nào bạn muốn tại đây. Bạn có thể thay đổi thông tin đăng nhập administrator bất kỳ lúc nào bằng cách sửa đổi các giá trị này và khởi động lại dịch vụ:

/ etc / concourse / web_enosystem
# These values can be used as-is CONCOURSE_SESSION_SIGNING_KEY=/etc/concourse/session_signing_key CONCOURSE_TSA_HOST_KEY=/etc/concourse/tsa_host_key CONCOURSE_TSA_AUTHORIZED_KEYS=/etc/concourse/authorized_worker_keys CONCOURSE_POSTGRES_SOCKET=/var/run/postgresql  # Change these values to match your environment CONCOURSE_BASIC_AUTH_USERNAME=sammy CONCOURSE_BASIC_AUTH_PASSWORD=theshark CONCOURSE_EXTERNAL_URL=http://servers_public_IP:8080 

Lưu file khi bạn hoàn tất.

Tiếp theo, tạo file môi trường cho quy trình worker :

  • sudo nano /etc/concourse/worker_environment

Bên trong, ta sẽ xác định vị trí của private key của worker, public key của TSA và folder nơi worker sẽ lưu trữ các file của nó. Ta cũng sẽ đặt địa chỉ nơi TSA có thể được tiếp cận, đó sẽ là localhost trong trường hợp của ta . Bạn có thể sử dụng các giá trị bên dưới mà không cần sửa đổi:

/ etc / concourse / worker_enosystem
# These values can be used as-is CONCOURSE_WORK_DIR=/var/lib/concourse CONCOURSE_TSA_WORKER_PRIVATE_KEY=/etc/concourse/worker_key CONCOURSE_TSA_PUBLIC_KEY=/etc/concourse/tsa_host_key.pub CONCOURSE_TSA_HOST=127.0.0.1:2222 

Lưu file khi bạn hoàn tất.

Tạo User Hệ thống Chuyên dụng và Điều chỉnh Quyền

Trước khi tiếp tục, ta nên tạo một user Linux chuyên dụng để chạy quy trình web Concourse. Điều này sẽ cho phép ta bắt đầu dịch vụ trên web với các quyền hạn chế.

Do cách PostgreSQL xử lý xác thực theo mặc định, điều quan trọng là tên user phải trùng với tên user PostgreSQL mà ta đã tạo trước đó. Tạo user hệ thống và group được gọi là concourse bằng lệnh :

  • sudo adduser --system --group concourse

Ta có thể cấp cho user mới quyền sở hữu đối với folder /etc/concourse và nội dung của nó bằng lệnh :

  • sudo chown -R concourse:concourse /etc/concourse

Các file môi trường chứa một số dữ liệu nhạy cảm như tên user và password quản trị cho server CI. Điều chỉnh quyền của các file môi trường để regular user không thể đọc hoặc sửa đổi các giá trị trong các file đó:

  • sudo chmod 600 /etc/concourse/*_environment

Nội dung cấu hình của ta hiện thuộc sở hữu của user hệ thống concourse với các quyền hạn chế dành cho user khác.

Tạo các file đơn vị Systemd cho các quy trình Web và Worker

Bây giờ ta đã sẵn sàng để xác định các file đơn vị Concourse CI sẽ khởi động và quản lý các quy trình ứng dụng. Ta sẽ tạo một file cho quy trình web xử lý các thành phần TSA và ATC và một file cho quy trình worker xử lý containers cho các việc đường ống.

Tạo file đơn vị web phòng chờ

Bắt đầu bằng cách tạo file concourse-web.service trong file /etc/systemd/system :

  • sudo nano /etc/systemd/system/concourse-web.service

Bên trong, dán các nội dung sau:

/etc/systemd/system/concourse-web.service
[Unit] Description=Concourse CI web process (ATC and TSA) After=postgresql.service  [Service] User=concourse Restart=on-failure EnvironmentFile=/etc/concourse/web_environment ExecStart=/usr/local/bin/concourse web  [Install] WantedBy=multi-user.target 

Phần đầu tiên của file đặt mô tả đơn vị cho quy trình web và cho biết đơn vị này nên được bắt đầu sau đơn vị PostgreSQL khi quyết định đặt hàng.

Phần [Service] xác định cách dịch vụ sẽ được chạy. Ta sẽ chạy dịch vụ với quyền là user concourse mà ta đã cấu hình trước đó và ta yêu cầu systemd tự động khởi động lại dịch vụ nếu nó không thành công, điều này có thể hữu ích nếu quá trình chết do hạn chế bộ nhớ hoặc các vấn đề tương tự. Ta tải file web_environment mà ta đã xác định trước đó để cài đặt môi trường và ta bắt đầu quy trình thực tế bằng cách gọi concourse web .

Phần [Install] cho systemd biết cách liên kết thiết bị với thứ tự khởi động hệ thống nếu ta cấu hình dịch vụ để bắt đầu khi server khởi động .

Lưu file khi bạn hoàn tất.

Tạo file đơn vị công nhân phòng chờ

Tiếp theo, mở một file tương tự để xác định quy trình worker :

  • sudo nano /etc/systemd/system/concourse-worker.service

Bên trong, dán các nội dung sau:

/etc/systemd/system/concourse-worker.service
[Unit] Description=Concourse CI worker process After=concourse-web.service  [Service] User=root Restart=on-failure EnvironmentFile=/etc/concourse/worker_environment ExecStart=/usr/local/bin/concourse worker  [Install] WantedBy=multi-user.target 

Đơn vị này hoạt động tương tự như đơn vị concourse-web . Lần này, ta yêu cầu hệ thống bắt đầu quy trình worker sau khi quy trình web Concourse đã được khởi động. Các worker quá trình được điều hành như là root user thay vì concourse vì nó đòi hỏi quyền quản trị cho quản lý container. Ta tải file worker_environment và sử dụng lệnh concourse worker để bắt đầu quá trình.

Lưu file khi bạn hoàn tất.

Điều chỉnh Tường lửa và Khởi động Dịch vụ

Với các file đơn vị của ta tại chỗ, giờ đây ta có thể cho phép truy cập thông qua firewall và khởi động các dịch vụ.

Quá trình web sẽ lắng nghe các kết nối trên cổng 8080, vì vậy ta cần mở quyền truy cập vào cổng đó trong firewall ufw :

  • sudo ufw allow 8080

Các containers được quy trình worker sử dụng yêu cầu quyền truy cập chuyển tiếp để chúng có thể truy cập internet và giải quyết các truy vấn DNS một cách chính xác. Ta có thể kích hoạt điều này bằng lệnh :

  • sudo ufw default allow routed

Bây giờ ta có thể bắt đầu dịch vụ của bạn bằng lệnh :

  • sudo systemctl start concourse-web concourse-worker

Ta có thể kiểm tra xem cả hai dịch vụ đã được khởi động chính xác hay chưa bằng lệnh :

  • sudo systemctl status concourse-web concourse-worker
Output
● concourse-web.service - Concourse CI web process (ATC and TSA) Loaded: loaded (/etc/systemd/system/concourse-web.service; disabled; vendor preset: enabled) Active: active (running) since Thu 2017-05-11 20:18:16 UTC; 1min 40s ago Main PID: 9954 (concourse) Tasks: 7 Memory: 100.0M CPU: 2.058s CGroup: /system.slice/concourse-web.service └─9954 /usr/local/bin/concourse web May 11 20:19:51 testatc concourse[9954]: {"timestamp":"1494533991.818562269","source":"tsa","message":"tsa.connection.keepalive","log_level":1,"data":{"remote":"127.0.0.1:48764","session":"1","type":"keepalive"}} . . . ● concourse-worker.service - Concourse CI worker process Loaded: loaded (/etc/systemd/system/concourse-worker.service; disabled; vendor preset: enabled) Active: active (running) since Thu 2017-05-11 20:18:16 UTC; 1min 39s ago Main PID: 9960 (concourse) Tasks: 9 Memory: 619.6M CPU: 20.353s CGroup: /system.slice/concourse-worker.service └─9960 /usr/local/bin/concourse worker May 11 20:19:12 testatc concourse[9960]: {"timestamp":"1494533952.909682751","source":"tsa","message":"tsa.connection.channel.forward-worker.heartbeat.start","log_level":1,"data":{"remote":"127.0.0.1:48764","session":"1.1.1.7","worker-address":"127.0.0.1:38993","worker-platform":"linux","worker-tags":""}} . . .

Kiểm tra xem cả hai dịch vụ đều đọc “hoạt động (đang chạy)” và các dòng log không chứa bất kỳ lỗi rõ ràng nào. Đặc biệt chú ý đến dịch vụ web đảm bảo rằng các dòng log không chỉ ra sự cố kết nối với database .

Nếu các dịch vụ khởi động thành công, hãy kích hoạt chúng để chúng khởi động mỗi khi server khởi động:

  • sudo systemctl enable concourse-web concourse-worker

Kiểm tra quyền truy cập trên dòng lệnh và thông qua giao diện web

Bây giờ các dịch vụ Concourse đang chạy, ta nên kiểm tra xem ta có quyền truy cập hay không.

Kiểm tra quyền truy cập trên dòng lệnh

Đầu tiên, hãy kiểm tra xem ta có thể truy cập dịch vụ Concourse bằng ứng dụng client dòng lệnh fly .

Ta phải đăng nhập bằng tên user và password quản trị mà ta đã cấu hình trong file /etc/concourse/web_environment bằng cách sử dụng lệnh con login . Một file binary fly đơn lẻ được dùng để liên hệ và quản lý nhiều server Concourse, vì vậy lệnh sử dụng một khái niệm gọi là “mục tiêu” làm alias cho các server khác nhau. Ta sẽ gọi mục tiêu của bạn là "cục bộ" để đăng nhập vào server Concourse local :

  • fly -t local login -c http://127.0.0.1:8080

Bạn sẽ được yêu cầu nhập tên user và password cho group main , ta đã đặt tên user và password mà ta đã đặt trong file web_environments . Sau khi nhập thông tin đăng nhập của bạn, "mục tiêu đã lưu" sẽ được hiển thị:

Output
logging in to team 'main' username: sammy password: target saved

Điều này cho thấy rằng ta đã có thể đăng nhập thành công. Trong khi ta ở đây, hãy xác minh quy trình công nhân có thể đăng ký thành công thành phần TSA bằng lệnh :

  • fly -t local workers
Output
name containers platform tags team state version concourse-server 0 linux none none running 1.0

Lệnh fly được sử dụng để cấu hình đường ống và quản lý dịch vụ Concourse CI. Lệnh fly help cung cấp thông tin về các lệnh bổ sung.

Kiểm tra quyền truy cập thông qua giao diện web

Tiếp theo, kiểm tra quyền truy cập web bằng cách truy cập địa chỉ IP server của bạn, sau đó là :8080 trong trình duyệt web:

http://servers_public_IP:8080 

Bạn có thể truy cập trang Concourse CI ban đầu:

Màn hình ban đầu của Concourse CI

Từ đây, bạn có thể tùy chọn tải lệnh fly xuống máy tính local của bạn dưới dạng ứng dụng client dòng lệnh bằng cách nhấp vào hình ảnh tương ứng với nền tảng của bạn. Điều này cho phép bạn quản lý môi trường CI của bạn mà không cần đăng nhập vào server . Hãy nhớ cung cấp địa chỉ IP công cộng của server của bạn thay vì 127.0.0.1 khi đăng nhập bằng fly lần đầu tiên (đọc cảnh báo về mã hóa bên dưới trước khi đăng nhập từ xa).

Nếu bạn nhấp vào liên kết đăng nhập ở góc trên bên phải, bạn có thể đăng nhập vào giao diện web. Đầu tiên, bạn cần chọn group của bạn . Group chính , là group quản trị, là lựa chọn khả dụng duy nhất theo mặc định:

Concourse CI chọn  group  chính

Trên trang tiếp theo, bạn cần nhập thông tin đăng nhập của bạn .

Cảnh báo : Giao diện web và cổng API do Concourse CI cung cấp không được mã hóa theo mặc định, vì vậy tên user và password của bạn sẽ được gửi đến server dưới dạng văn bản thuần túy. Nếu bạn định sử dụng cài đặt này cho bất kỳ mục đích nào khác ngoài mục đích đánh giá, hãy bảo vệ giao diện web bằng SSL trước khi đăng nhập. Làm theo hướng dẫn của ta về cách cài đặt Reverse Proxy Nginx được bảo vệ bằng SSL cho Concourse CI để cấu hình truy cập an toàn.

Sau khi nhập thông tin đăng nhập bạn đã cấu hình trong file web_environment , bạn sẽ được đăng nhập và đưa trở lại giao diện trình giữ chỗ mặc định:

Concourse CI chọn  group  chính

Sau khi bạn gửi cấu hình đường ống của bạn đến server một cách fly , màn hình này sẽ được thay thế bằng một giao diện nơi bạn có thể theo dõi hoạt động đường ống của bạn .

Kết luận

Trong hướng dẫn này, ta đã cài đặt PostgreSQL và các file binary Concourse, cài đặt khóa mã hóa và cấu hình truy cập mạng và truy cập mạng. Sau khi khởi động các dịch vụ, ta đăng nhập local bằng lệnh fly và truy cập giao diện web để xác nhận chức năng.

Như đã đề cập trước đó, trước khi bạn sử dụng Concourse cho công việc thực tế, điều quan trọng là phải bảo vệ web và cổng API bằng SSL. Làm theo hướng dẫn của ta về cách cài đặt Reverse Proxy SSL cho Concourse CI với Nginx để cấu hình quyền truy cập an toàn vào server của bạn trước khi tương tác với server từ xa.

Để tìm hiểu cách sử dụng fly để thêm đường ống dẫn vào server Concourse của bạn, hãy xem ví dụ "hello world" trong tài liệu Concourse .


Tags:

Các tin liên quan

Cách giám sát server và dịch vụ bằng Icinga trên Ubuntu 16.04
2017-05-05
Cách thiết lập đồng bộ hóa thời gian trên Ubuntu 16.04
2017-04-28
Cách quản lý log với Graylog 2 trên Ubuntu 16.04
2017-04-25
Cách cài đặt Webmin trên Ubuntu 16.04
2017-04-21
Cách cài đặt và cấu hình OrientDB trên Ubuntu 16.04
2017-03-24
how-to-monitor-system-metrics-with-the-tick-stack-on-ubuntu-16-04
2017-03-16
Cách cài đặt và cấu hình Postfix trên Ubuntu 16.04
2017-03-16
Cách cấu hình client FreeIPA trên Ubuntu 16.04
2017-03-08
Cách cài đặt Moodle trên Ubuntu 16.04
2017-03-02
Cách cài đặt và bảo mật MongoDB trên Ubuntu 16.04
2017-02-24