Termux давно перестал быть «только терминалом»: сегодня на Android реально организовать локальный контур для разработки, сборки образов, запуска Kubernetes‑lite (k3s) и последующего деплоя микросервисов. В этой статье покажу практический подход к построению небольшого кластера (k3s) в локальной среде, чтобы протестировать сервис‑дискавери, сетевую связность, горизонтальное масштабирование и наблюдаемость без сложной инфраструктуры.
Фокус: Node.js/Go микросервисы, контейнеризация, k3s, Ingress/LB‑подобные сценарии для локального доступа и шаблоны для расширения системы.
Архитектура решения: что именно мы собираем
В рамках локальной разработки обычно достаточно следующей структуры:
- Termux — рабочая среда, где вы пишете код, собираете образы и управляете деплоем.
- k3s (Kubernetes‑lite) — локальный кластер, в котором поды выполняют ваши микросервисы.
- Контейнеризация — Docker/Buildah‑подобный процесс в Termux (или сборка на внешней машине с последующим переносом образов) в зависимости от доступности окружения.
- Сервис‑дискавери — доступ между сервисами по DNS‑именам Kubernetes (например,
service-name.namespace.svc.cluster.local). - Масштабирование — через Deployment и replicas + обновления.
Важно: мы делаем локальную сеть и тестируем функциональность. Ниже я не использую сценарии для обхода блокировок.
Требования и подготовка окружения в Termux
Подготовьте Android‑устройство и Termux. Базовые требования:
- Termux установлен
- Достаточно места под контейнеры/образы
- Сетевая связность внутри вашей локальной среды (или через устройство‑хост, если кластер поднимается не строго «на телефоне»)
Начнем с обновления пакетов и установки минимального набора утилит. В зависимости от вашей сборки Termux‑репозитория названия пакетов могут отличаться, но логика остается той же.
pkg update && pkg upgrade -y
pkg install -y git curl ca-certificates tar gzip unzip
pkg install -y nodejs npm
pkg install -y golangЕсли вам нужен CLI‑подход к Kubernetes и k3s, обычно требуется либо бинарник k3s, либо установка через удобный скрипт. В этой статье ориентируемся на «локальный кластер» через k3s и стандартные Kubernetes‑манифесты.
Контейнеризация микросервисов: Node.js и Go
Ниже — два примера микросервисов с минимальным API. Логику выбирайте под ваш домен, а шаблоны используйте как основу.
Пример: Node.js микросервис
Создайте проект:
mkdir -p ~/projects/k3s-demo/node-svc
cd ~/projects/k3s-demo/node-svc
npm init -yУстановите зависимости (минимально — express):
npm install expressСоздайте server.js:
cat > server.js <<'EOF'
const express = require('express');
const app = express();
const port = process.env.PORT || 3000;
app.get('/healthz', (req, res) => res.status(200).json({ ok: true }));
app.get('/hello', (req, res) => {
const from = process.env.HOSTNAME || 'unknown';
res.json({ message: 'Hello from Node.js', from });
});
app.listen(port, () => {
console.log(Node service listening on ${port});
});
EOFДобавьте Dockerfile. Даже если вы собираете не внутри Termux, этот файл пригодится для переноса/сборки на любой среде:
cat > Dockerfile <<'EOF'
FROM node:20-alpine
WORKDIR /app
COPY package.json ./
RUN npm ci --only=production
COPY . .
ENV PORT=3000
EXPOSE 3000
CMD ["node", "server.js"]
EOFСоберите образ. Команда зависит от того, есть ли у вас доступ к Docker/daemon на Android. Если вы собираете локально в Termux — используйте доступный движок. Если daemon недоступен, сборку логичнее делать на ПК/сервере и переносить образ в registry. Для примера показан стандартный вариант с Docker:
docker build -t local/node-svc:1.0.0 .Если Docker внутри Termux недоступен, можно собрать образ на внешней машине, а затем загрузить в registry или перенести через docker save/docker load (в зависимости от вашей инфраструктуры разработки).
Пример: Go микросервис
Создайте проект:
mkdir -p ~/projects/k3s-demo/go-svc
cd ~/projects/k3s-demo/go-svc
go mod init go-svcСоздайте main.go:
cat > main.go <<'EOF'
package main
import (
"encoding/json"
"net/http"
"os"
)
func main() {
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
http.HandleFunc("/healthz", func(w http.ResponseWriter, r http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
_ = json.NewEncoder(w).Encode(map[string]any{"ok": true})
})
http.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
from := os.Getenv("HOSTNAME")
if from == "" {
from = "unknown"
}
_ = json.NewEncoder(w).Encode(map[string]any{
"message": "Hello from Go",
"from": from,
})
})
addr := ":" + port
http.ListenAndServe(addr, nil)
}
EOFДобавьте Dockerfile:
cat > Dockerfile <<'EOF'
FROM golang:1.22-alpine AS builder
WORKDIR /src
COPY . .
RUN go build -o /app/server main.go
FROM alpine:3.20
WORKDIR /app
COPY --from=builder /app/server /app/server
ENV PORT=8080
EXPOSE 8080
CMD ["/app/server"]
EOFСоберите образ:
docker build -t local/go-svc:1.0.0 .Подготовка Kubernetes‑lite (k3s)
k3s предоставляет минимально необходимый набор компонентов Kubernetes для разработки. В зависимости от того, поднимаете ли вы кластер прямо на телефоне или на отдельном хосте, схема шагов может отличаться. Логику манифестов ниже можно применять в любом варианте.
Сценарий для локального кластера (типовой): вы запускаете k3s, получаете доступ к Kubernetes API, а затем применяете манифесты через kubectl.
Базовая проверка после поднятия k3s:
kubectl get nodes
kubectl get pods -ANamespace и образы
Создадим рабочее пространство имен:
kubectl create namespace demoДалее определим, как будут доставляться образы. На практике:
- Если у вас локальный registry — используйте его URL в тегах образов.
- Если у вас нет registry — иногда настраивают локальное подключение образов к runtime (зависит от окружения).
Для примера я покажу манифесты, где образы находятся по local/.... В реальном проекте подставьте ваш registry/способ доставки образов.
Деплой микросервисов: Deployment + Service
Node.js Deployment и Service
Создайте манифест node-deployment.yaml:
cat > node-deployment.yaml <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
name: node-svc
namespace: demo
spec:
replicas: 2
selector:
matchLabels:
app: node-svc
template:
metadata:
labels:
app: node-svc
spec:
containers:
- name: node-svc
image: local/node-svc:1.0.0
ports:
- containerPort: 3000
readinessProbe:
httpGet:
path: /healthz
port: 3000
initialDelaySeconds: 3
periodSeconds: 10
livenessProbe:
httpGet:
path: /healthz
port: 3000
initialDelaySeconds: 10
periodSeconds: 20
EOFСоздайте Service node-service.yaml:
cat > node-service.yaml <<'EOF'
apiVersion: v1
kind: Service
metadata:
name: node-svc
namespace: demo
spec:
selector:
app: node-svc
ports:
- name: http
port: 80
targetPort: 3000
type: ClusterIP
EOFПримените манифесты:
kubectl apply -f node-deployment.yaml
kubectl apply -f node-service.yamlGo Deployment и Service
Создайте go-deployment.yaml:
cat > go-deployment.yaml <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
name: go-svc
namespace: demo
spec:
replicas: 2
selector:
matchLabels:
app: go-svc
template:
metadata:
labels:
app: go-svc
spec:
containers:
- name: go-svc
image: local/go-svc:1.0.0
ports:
- containerPort: 8080
readinessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 3
periodSeconds: 10
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 10
periodSeconds: 20
EOFСоздайте go-service.yaml:
cat > go-service.yaml <<'EOF'
apiVersion: v1
kind: Service
metadata:
name: go-svc
namespace: demo
spec:
selector:
app: go-svc
ports:
- name: http
port: 80
targetPort: 8080
type: ClusterIP
EOFПримените:
kubectl apply -f go-deployment.yaml
kubectl apply -f go-service.yamlСервис‑дискавери: проверяем DNS внутри кластера
Kubernetes автоматически создает DNS‑записи для сервисов. Для сервисов в namespace demo доступ обычно выглядит так:
node-svc(внутри того же namespace)node-svc.demo.svc.cluster.local(полный FQDN)- Аналогично для
go-svc
Проверим связность через временный Pod с curl. Для удобства создадим Job или однократный Pod. Например, используйте BusyBox:
kubectl run -n demo tmp-curl --image=busybox:1.36 --restart=Never -- /bin/sh -c "sleep 2 && wget -qO- http://node-svc/hello && echo && wget -qO- http://go-svc/hello"Если все настроено, вы увидите JSON‑ответы от обоих сервисов. Это и есть базовая «магия» сервис‑дискавери.
Маршрутизация для локального доступа: Ingress (опционально)
В локальном k3s часто удобно использовать Ingress для доступа снаружи к ClusterIP сервисам. Конкретный контроллер зависит от вашей конфигурации k3s.
Если у вас есть ingress‑контроллер, создайте, например, простой Ingress для Node.js сервиса. Подставьте доступный host (в локальной сети) или используйте wildcard/локальный домен в зависимости от ваших настроек.
cat > node-ingress.yaml <<'EOF'
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: node-ingress
namespace: demo
spec:
rules:
- host: node.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: node-svc
port:
number: 80
EOFПримените:
kubectl apply -f node-ingress.yamlДоступ извне будет зависеть от того, как вы резолвите node.local в вашей локальной сети. Часто используют записи в /etc/hosts на тестовом устройстве или локальный DNS.
Масштабирование: горизонтальное увеличение replicas
Для базового горизонтального масштабирования достаточно увеличить spec.replicas в Deployment.
Например, увеличим Node.js до 4 реплик:
kubectl scale deployment/node-svc -n demo --replicas=4Проверим:
kubectl get pods -n demo -l app=node-svc -o wideДля проверки, что масштабирование работает как ожидается, вызывайте /hello и смотрите на поле from (hostname контейнеров), чтобы убедиться, что запросы обслуживаются разными Pod‑ами.
Обновления версий: rolling update
Чтобы обновить сервис, поменяйте образ и повторно примените манифест или используйте:
kubectl set image deployment/node-svc -n demo node-svc=local/node-svc:1.1.0Следите за статусом развертывания:
kubectl rollout status deployment/node-svc -n demo
kubectl get pods -n demo -l app=node-svc -wНаблюдаемость в локальной среде: что контролировать
Минимальный набор, который стоит держать в привычке:
- Статусы Pod:
kubectl get pods -n demo - Логи контейнеров:
kubectl logs -n demo <pod> - События (events):
kubectl get events -n demo --sort-by=.metadata.creationTimestamp
Пример просмотра логов:
kubectl logs -n demo -l app=go-svc --tail=100Практические советы для Termux + k3s
- Разделяйте сборку и деплой: если сборка образов в Termux неудобна из‑за ограничений Android‑окружения, логичнее собирать на ПК, а деплой делать в k3s.
- Тестируйте DNS и сервисы отдельно: сначала убедитесь, что ClusterIP сервисы доступны изнутри (tmp‑curl), и только потом подключайте Ingress.
- Используйте healthz: readiness/liveness сильно упрощают работу в маленьком кластере.
- Думайте про версионирование: фиксируйте теги образов (semver), чтобы rolling update был предсказуемым.
Выводы
Мы рассмотрели практический путь разработки и деплоя микросервисов Node.js и Go в локальной Kubernetes‑lite среде k3s: контейнеризация через Dockerfile, развертывание Deployment+Service, проверка сервис‑дискавери через Kubernetes DNS и базовое масштабирование replicas. Такой подход отлично подходит для обучения, прототипирования и отладки микросервисной архитектуры в «домашних» условиях.
Если хотите быстрее пройти путь от идеи до работающего контура (k3s, контейнеризация, манифесты, сетевые настройки, локальный доступ и best practices), обратитесь в РыбинскЛАБ — мы поможем с внедрением и настройкой под ваш сценарий разработки.