Tạo folder bắt đâù cài đặt Komodo core:
mkdir komodo
cd komodo
sudo mkdir -p \
./data/mongo-db \
./data/mongo-configdb \
./data/repo-cache \
./backupsBạn có thể dụng command để tạo chuỗi random dài:
openssl rand -hex 32
03af3ddcc5xxxxx60f40beb1ba6b1985ccb1d798c142f2bb06996d232Create compose.env
TZ=Asia/Singapore
# Public URL Core mà browser và Periphery truy cập
KOMODO_HOST=http://192.168.101.36:9120
# MongoDB
KOMODO_DB_USERNAME=komodo
KOMODO_DB_PASSWORD=03af3ddcc5xxxxx60f40beb1ba6b1985ccb1d798c142f2bb06996d232
# Local authentication
KOMODO_LOCAL_AUTH=true
KOMODO_INIT_ADMIN_USERNAME=admin
KOMODO_INIT_ADMIN_PASSWORD=03af3ddcc5xxxxx60f40beb1ba6b1985ccb1d798c142f2bb06996d232
KOMODO_JWT_SECRET=03af3ddcc5xxxxx60f40beb1ba6b1985ccb1d798c142f2bb06996d232
# Core-to-Periphery và webhook secrets
KOMODO_PASSKEY=03af3ddcc5xxxxx60f40beb1ba6b1985ccb1d798c142f2bb06996d232
KOMODO_WEBHOOK_SECRET=03af3ddcc5xxxxx60f40beb1ba6b1985ccb1d798c142f2bb06996d232Tạo file compose.yaml (version mới không cần tạo file docker-compse.yaml nữa)
services:
mongo:
image: mongo:8
container_name: komodo-mongo
restart: unless-stopped
command: --quiet --wiredTigerCacheSizeGB 0.25
environment:
MONGO_INITDB_ROOT_USERNAME: ${KOMODO_DB_USERNAME}
MONGO_INITDB_ROOT_PASSWORD: ${KOMODO_DB_PASSWORD}
volumes:
- ./data/mongo-db:/data/db
- ./data/mongo-configdb:/data/configdb
networks:
- komodo-internal
core:
image: ghcr.io/moghtech/komodo-core:2.2.0
container_name: komodo-core
restart: unless-stopped
depends_on:
- mongo
env_file:
- ./compose.env
environment:
KOMODO_DATABASE_ADDRESS: mongo:27017
KOMODO_DATABASE_USERNAME: ${KOMODO_DB_USERNAME}
KOMODO_DATABASE_PASSWORD: ${KOMODO_DB_PASSWORD}
ports:
- "9120:9120"
volumes:
- ./data/repo-cache:/repo-cache
networks:
- komodo-internal
networks:
komodo-internal:
name: komodo-internalTiếp đến là câu lệnh run docker compose:
docker compose --env-file compose.env up -dBạn login vào IP-host:9120
Install Komodo Peripheri
Trước tiên bạn cần tạo Onboarding key:
Bạn vào Setting -> Onboarding -> Click: New Onboarding Key

Bạn khai bao các thứ


Bạn copy the key và chuẩn bị cho công lệnh chạy trên Periphery
curl -sSL https://raw.githubusercontent.com/moghtech/komodo/main/scripts/setup-periphery.py \
| python3 - \
--core-address="http://komodo-core-domain-or-ip" \
--connect-as="$(hostname)" \
--onboarding-key="<ONBOARDING_KEY_CUA_BAN>"Xoá Komodo Periphery
Bước 1: Gỡ cài đặt (Uninstall)
- Dừng và vô hiệu hóa service đang chạy:
sudo systemctl stop periphery
sudo systemctl disable peripheryXóa file service của Systemd và tải lại daemon:
sudo rm /etc/systemd/system/periphery.service
sudo systemctl daemon-reloadXóa file nhị phân (binary):
File thực thi của periphery thường được đặt ở thư mục /usr/local/bin/ (với tài khoản root).
sudo rm /usr/local/bin/peripheryNếu bạn từng cài đặt với cờ --user bằng quyền user thường, file có thể nằm ở ~/.local/bin/periphery).
- Xóa thư mục cấu hình và khóa chứng thực (Keys):
Periphery lưu các file cấu hìnhperiphery.config.tomlvà các cặp khóa (public/private keys) tại/etc/komodo. Việc xóa thư mục này đảm bảo quá trình cài lại sẽ sinh ra cặp khóa mới hoàn toàn (rất quan trọng nếu bạn thay đổi Core).github+1
sudo rm -rf /etc/komodoCài đặt Komodo Core

Chúng ta sẽ cài đặt Komodo trên k8s.
#kustomizaion:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: komodo
resources:
- komodo-auth-secret.json
helmCharts:
- name: komodo
includeCRDs: false
releaseName: komodo
version: 0.1.1
repo: https://antiantiops.github.io/komodo-helm-chart
valuesFile: values_helm.yaml
namespace: komodo
# helm-values.yaml
###############
# Production values for the Komodo Helm chart.
# Credentials reside in the pre-created Kubernetes Secret komodo-auth, not Git.
existingSecret:
name: komodo-auth
komodo:
host: http://komodo.nimtechnology.com
localAuth: true
timezone: Asia/Ho_Chi_Minh
ingress:
enabled: true
className: nginx
annotations: {}
hosts:
- host: komodo.nimtechnology.com
paths:
- path: /
pathType: Prefix
tls: []
persistence:
config:
enabled: true
size: 1Gi
storageClass: longhorn
repoCache:
enabled: true
size: 10Gi
storageClass: longhorn
mongo:
persistence:
enabled: true
size: 10Gi
storageClass: longhorn
Tiếp theo chúng ta tạo secret cấp cho mongodb, komodo.
{
"apiVersion": "v1",
"kind": "Secret",
"metadata": {
"name": "komodo-auth",
"namespace": "komodo"
},
"type": "Opaque",
"data": {
"komodo-init-admin-password": "TlE5cnNuOXFycmlCSxxxxx1CMlA3MDZaU0RQNk4=",
"komodo-jwt-secret": "bVIvc1VwUlpHSXpmd2phcCt1V29DY2czMkdpcWXXXXNaUUFJQVZ2b1d1MVZhNWNjbFg4QTFrUWxUNQ==",
"komodo-passkey": "ZU9SNG1KaWMxbXBrc1XXXXnh4U3d3QUFIU2NodGl1OGtqMDZLR3RrST0=",
"komodo-webhook-secret": "UzE5NDRNZkZlWlXXXXN0JFbzZRcDFkd1VQVzA3QllCRXZrVDk1UT0=",
"mongo-root-password": "VktFNFF3bndVWURkcFXXXXXb1dRZTFhSUExTzZyT3Zub1Uraz0="
}
}
Mô hình webhook của

Cách lấy file python theo release:
TAG=v2.3.1
COMMIT="$(git ls-remote https://github.com/moghtech/komodo.git "refs/tags/${TAG}" | awk '{print $1}')"
CHECKSUM="$(curl --fail --silent --show-error --location \
"https://raw.githubusercontent.com/moghtech/komodo/${COMMIT}/scripts/setup-periphery.py" \
| shasum -a 256 | awk '{print $1}')"
printf 'commit=%s\nchecksum=sha256:%s\nversion=%s\n' \
"$COMMIT" "$CHECKSUM" "$TAG"Komodo Stack
Sau khi stack deploy cái docker compose.
thì nó cần run 1 lệnh là docker compose config để lưu lại lần mới nhất komodo đã deploy thử gì.
và nếu lần sau bạn change trên github thì bạn có thấy được bạn đã thay đổi gì so với lần gần nhất mà komodo đã deploy.

Điều này cho chúng ta thấy một khái niệm là project trong docker.
chúng ta sẽ cần run command để show các docker đang chạy trong hosts
docker ps -a
Hoặc lệnh
docker compose ls
NAME STATUS CONFIG FILES
hihi running(1) /opt/hihi/docker-compose.yml
node-exporter running(2) /opt/data/node-exporter/docker-compose.ymlChúng ta sẽ dùng lệnh
docker inspect node-exporter --format '{{ index .Config.Labels "com.docker.compose.project" }}'
node-exporterdocker network inspect node-exporter_node-exporter_network \
--format '{{range .IPAM.Config}}{{.Subnet}} {{.Gateway}}{{end}}'
192.168.112.0/24 192.168.112.1bạn thấy project nối vào network name
Vì stack là nim-devops-host nên bạn không cần khai báo project name trong config stack.
như ảnh dưới

nếu project_name để trống komodo sẽ lấy name của stack làm project name
Komodo Variables.
services:
nginx:
image: nginx:1.20-alpine
container_name: komodo-demo-nginx
restart: unless-stopped
environment:
TEST_VAR: this_is_secret
ports:
- "8080:80"
labels:
app.kubernetes.io/managed-by: komodo
demo: gitops
check: status
komodo.gitops.probe: "2026-07-21T18:22:00Z"Bạn thấy đó khi mà chúng ta environment chứa secret.
Nhưng giờ nếu chúng ta muốn push docker compose này lên github thi hoàn toàn không được vì nó chưa credential.
đầu tiên bạn sử dụng tính năng variables trong settings của komodo

tiếp đến bạn cần ghi nhận variable secret trong toml file.

[[stack]]
name = "demo-nginx"
description = "Nginx Docker Compose application managed by Komodo"
tags = ["demo", "gitops", "komodo-periphery"]
deploy = true
[stack.config]
server = "periphery-181"
git_account = "mrnim94"
repo = "mrnim94/komodo-gitops-demo"
branch = "master"
git_provider = "github.com"
file_paths = ["stacks/office-hcm/periphery-181/nginx-demo/compose.yaml"]
environment = """
TEST_VAR = [[TEST_VAR]]
"""tiếp đến là khai báo trong docker-compose.yaml
ame: nginx-ahihi
services:
nginx:
image: nginx:1.20-alpine
container_name: komodo-demo-nginx
restart: unless-stopped
environment:
TEST_VAR: ${TEST_VAR}
ports:
- "8080:80"
labels:
app.kubernetes.io/managed-by: komodo
demo: gitops
check: status
komodo.gitops.probe: "2026-07-21T18:22:00Z"
Lúc này mình execute vào trong container thì sẽ thấy environment là TEST_VAR

Komodo Actions
Một tính năng tự động hóa nâng cao cho phép viết kịch bản TypeScript để tương tác trực tiếp với Komodo API.
Dưới đây là thiết kế giải pháp và Template Action trên Komodo để triển khai hot patching/security update hàng loạt trên 10 máy chủ Debian, đồng thời kiểm tra tiến trình và trạng thái hệ thống theo thời gian thực.
Chúng ta có 2 cách là chạy command trên các server đã gắn tag

Ví dụ bạn install komodo periphery trên client nhưng quên gắn tag thì bạn có thể ấn tạo tag trên UI hoặc dụng file toml để tạo tag cho server.

Bạn có thế lấy convert của server này ra file toml và update để không bị mất config nào

[[server]]
name = "periphery-181"
tags = ["hotpatch-group", "office-hcm"]
[server.config]
enabled = trueLúc này file action watch các server có tag là hotpatch-group
#file name: hotpatch-action.toml
[[action]]
name = "debian-hotpatching"
[action.config]
# Lên lịch chạy tự động (ví dụ: 03:00 sáng Chủ nhật hàng tuần)
schedule = "0 3 * * 0"
# Nội dung kịch bản TypeScript
script = """
const servers = await komodo.read("ListServers", {
query: { tags: ["hotpatch-group"] },
});
for (const server of servers) {
const hotPatchCommand = [
"export DEBIAN_FRONTEND=noninteractive",
"sudo apt update -q",
"sudo apt-get --with-new-pkgs upgrade -y -q",
"sudo apt install -y needrestart",
"echo '--- [1] PROCESS RESTART STATUS ---'",
"sudo needrestart -b || true",
"echo '--- [2] UPTIME ---'",
"uptime",
"echo '--- [3] KERNEL ---'",
"uname -r",
].join(" && ");
await komodo.execute_server_terminal(
{
server: server.name,
terminal: "hotpatch-job",
command: hotPatchCommand,
init: {
command: "bash",
recreate: "Always",
},
},
{
onLine: (line) => console.log(`[${server.name}] ${line}`),
onFinish: (code) => console.log(`[${server.name}] Finished code: ${code}`),
}
);
}
"""Hoặc bạn muốn chạy thẳng trên server chúng ta đã có:
[[action]]
name = "debian-hotpatching"
[action.config]
# Lên lịch chạy tự động (03:00 sáng Chủ nhật hàng tuần)
#schedule_format = "Cron"
#schedule = "0 0 3 * * 0"
#schedule_enabled = true
# Nội dung kịch bản TypeScript
file_contents = """
// Khai báo danh sách server cần hotpatch
const serverNames = ["periphery-181"];
for (const name of serverNames) {
const server = { name };
const hotPatchCommand = [
"export DEBIAN_FRONTEND=noninteractive",
"sudo apt update -q",
"sudo apt-get --with-new-pkgs upgrade -y -q",
"sudo apt install -y needrestart",
"echo '--- [1] PROCESS RESTART STATUS ---'",
"sudo needrestart -b || true",
"echo '--- [2] UPTIME ---'",
"uptime",
"echo '--- [3] KERNEL ---'",
"uname -r",
].join(" && ");
await komodo.execute_server_terminal(
{
server: server.name,
terminal: "hotpatch-job",
command: hotPatchCommand,
init: {
command: "bash",
recreate: "Always",
},
},
{
onLine: (line) => console.log(`[${server.name}] ${line}`),
onFinish: (code) => console.log(`[${server.name}] Finished code: ${code}`),
}
);
}
"""stdout sau khi chúng ta ấn run.

Bạn cũng có thể query các thông tin khác như là:
Bạn muốn chạy patching trên con server mà có Kernel: 6.12.94+deb13-amd64

[[action]]
name = "debian-hotpatching"
description = "Hotpatch servers running kernel 6.12.94+deb13-amd64"
[action.config]
# Schedule tắt — chạy tay qua Komodo UI khi cần
schedule_format = "Cron"
schedule = "0 0 3 * * 0"
schedule_enabled = false
# Nội dung kịch bản TypeScript
file_contents = """
const targetKernel = "6.12.94+deb13-amd64";
const servers = await komodo.read("ListServers", {});
const matchedServerNames: string[] = [];
for (const server of servers) {
const systemInfo = await komodo.read("GetSystemInformation", {
server: server.name,
});
const kernel = systemInfo.kernel ?? systemInfo.kernel_version ?? systemInfo.uname?.release;
console.log(`[${server.name}] kernel: ${kernel ?? "unknown"}`);
if (kernel === targetKernel) {
matchedServerNames.push(server.name);
}
}
console.log(`Matched ${matchedServerNames.length} server(s): ${matchedServerNames.join(", ") || "none"}`);
const hotPatchCommand = [
"export DEBIAN_FRONTEND=noninteractive",
"sudo apt update -q",
"sudo apt-get --with-new-pkgs upgrade -y -q",
"sudo apt install -y needrestart",
"echo '--- [1] PROCESS RESTART STATUS ---'",
"sudo needrestart -b || true",
"echo '--- [2] UPTIME ---'",
"uptime",
"echo '--- [3] KERNEL ---'",
"uname -r",
].join(" && ");
for (const serverName of matchedServerNames) {
await komodo.execute_server_terminal(
{
server: serverName,
terminal: "hotpatch-job",
command: hotPatchCommand,
init: {
command: "bash",
recreate: "Always",
},
},
{
onLine: (line) => console.log(`[${serverName}] ${line}`),
onFinish: (code) => console.log(`[${serverName}] Finished code: ${code}`),
}
);
}
"""- Query
glibctừng server. - Tạo
matchedServerNames. - In list server có glibc
2.41. - Chỉ chạy command
hostnamevàuptimetrên list đó.
[[action]]
name = "debian-hotpatching"
description = "List servers running glibc 2.41 with hostname and uptime"
[action.config]
# Schedule tắt — chạy tay qua Komodo UI khi cần
schedule_format = "Cron"
schedule = "0 0 3 * * 0"
schedule_enabled = false
# Nội dung kịch bản TypeScript
file_contents = """
const targetGlibc = "2.41";
const servers = await komodo.read("ListServers", {});
const matchedServerNames: string[] = [];
// Pha 1: chỉ query glibc, chưa chạy hostname hoặc uptime.
for (const server of servers) {
let glibc = "";
await komodo.execute_server_terminal(
{
server: server.name,
terminal: "glibc-check-job",
command: "dpkg-query -W -f='${Version}' libc6 2>/dev/null || true",
init: {
command: "bash",
recreate: "Always",
},
},
{
onLine: (line) => {
const value = line.trim();
if (value && !value.includes("Finished code")) glibc = value;
},
onFinish: (code) => console.log(`[glibc-check:${server.name}] ${glibc || "unavailable"} (code: ${code})`),
}
);
if (glibc.split("-")[0] === targetGlibc) matchedServerNames.push(server.name);
}
console.log(`glibc ${targetGlibc} servers: ${matchedServerNames.join(", ") || "none"}`);
// Pha 2: chỉ server đã nằm trong list mới query hostname và uptime.
for (const serverName of matchedServerNames) {
await komodo.execute_server_terminal(
{
server: serverName,
terminal: "glibc-info-job",
command: "printf 'hostname: '; hostname; printf 'uptime: '; uptime -p",
init: {
command: "bash",
recreate: "Always",
},
},
{
onLine: (line) => console.log(`[server:${serverName}] ${line}`),
onFinish: (code) => console.log(`[server:${serverName}] Finished code: ${code}`),
}
);
}
"""