Termux — мощная среда для разработки на Android, позволяющая запускать компиляторы, инструменты сборки и сетевые сервисы прямо на устройстве. В этой статье мы рассмотрим практический подход к разработке и деплою микросервисов на Go и Rust в Termux, с поддержкой gRPC и protobuf, а также с идеей автоматического масштабирования на уровне процесса/пула воркеров и оркестрации за пределами самого устройства.
Материал ориентирован на разработчиков, которым важно быстро прототипировать и затем переносить сервисы в более “серверный” контур.
Архитектура решения
Типичный микросервис на gRPC состоит из:
- IDL — описание контрактов в proto (сообщения, сервисы, методы)
- Сервер — реализация обработчиков gRPC
- Клиент — потребитель API (другой сервис или тестовый стенд)
- Транспорт — HTTP/2 поверх gRPC
- Слой сборки — генерация кода из protobuf
- Деплой — запуск и управление процессами
- Масштабирование — увеличение числа инстансов или воркеров
В Termux мы используем локальную сеть и запуск сервисов на устройстве. Для распределённого масштабирования обычно нужен внешний оркестратор (например, Kubernetes), а на устройстве — удобный аналог: запуск нескольких экземпляров сервиса и балансировка запросов на стороне “внешнего” компонента или простого локального балансировщика.
Подготовка Termux
Убедимся, что пакетный менеджер и базовые зависимости обновлены.
pkg update && pkg upgrade -yДалее установим базовый набор: компиляторы, утилиты, git.
pkg install -y git curl unzip tar ca-certificates clang make wget pkg-configДля сборки Rust может потребоваться стандартная toolchain — в большинстве случаев Termux-установка справится с этим через rustup или prebuilt.
Для протоколов и генерации кода нам пригодятся protobuf-инструменты и версии генераторов.
Установка Go, Rust и protobuf toolchain
В Termux есть разные варианты установки. Приведём практичный путь: используем установку инструментов из репозиториев/официальных сборок там, где это доступно.
Go
Если Go доступен через пакетный менеджер Termux, можно начать с него.
pkg install -y golangПроверим:
go versionRust
Установим Rust через rustup (универсальный подход для актуальных версий).
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | shПосле установки перезайдите в текущую сессию или выполните подгрузку:
source $HOME/.cargo/envПроверка:
rustc --version && cargo --versionprotobuf и генераторы
Для генерации кода из protobuf на Go и Rust обычно нужны:
- protoc (компилятор .proto)
- protoc-gen-go (генерация Go-кода)
- protoc-gen-go-grpc (gRPC для Go)
- protoc-gen-rust (protobuf-код для Rust) и tonic-build (генерация gRPC-обвязки)
Сначала поставим protoc, если он доступен:
pkg install -y protobufПроверим:
protoc --versionТеперь установим генераторы для Go:
go install google.golang.org/protobuf/cmd/protoc-gen-go@latestgo install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latestУбедимся, что каталог с бинарниками Go в PATH. Часто это $HOME/go/bin:
export PATH="$PATH:$HOME/go/bin"Проверка:
protoc-gen-go --version || trueДля Rust генерация gRPC обычно делается через tonic-build внутри сборочного скрипта, а не отдельными глобальными бинарниками (хотя protoc всё равно нужен).
Проект: общий proto-контракт
Создадим рабочую директорию и структуру:
mkdir -p grpc-termux/go-service grpc-termux/rust-service grpc-termux/protoОпределим контракт в grpc-termux/proto/echo.proto:
syntax = "proto3";
package echo;
option go_package = "echo/echopb;echopb";
service EchoService {
rpc Echo (EchoRequest) returns (EchoReply) {}
}
message EchoRequest {
string message = 1;
}
message EchoReply {
string message = 1;
}Задача протокола — простой echo, чтобы отладить связку gRPC + генерацию.
Реализация сервиса на Go
Создадим Go-модуль:
cd grpc-termux/go-service
go mod init grpc-termux/go-service || go mod init go-serviceСоберём зависимости:
go get google.golang.org/grpc@latest
go get google.golang.org/protobuf@latestДобавим генерацию protobuf в рамках проекта.
Вариант для простоты: сгенерировать в каталог ./echopb заранее.
mkdir -p echopb
protoc -I ../proto --go_out=. --go-grpc_out=. ../proto/echo.protoВажно: параметры генерации зависят от версии protoc-gen-go и расположения опций option go_package.
Далее реализуем сервер в main.go:
package main
import (
"context"
"log"
"net"
"os"
"google.golang.org/grpc"
echopb "grpc-termux/go-service/echopb/echo"
)
type server struct {
echopb.UnimplementedEchoServiceServer
}
func (s server) Echo(ctx context.Context, req echopb.EchoRequest) (echopb.EchoReply, error) {
return &echopb.EchoReply{Message: req.Message}, nil
}
func main() {
addr := os.Getenv("GRPC_ADDR")
if addr == "" {
addr = ":50051"
}
lis, err := net.Listen("tcp", addr)
if err != nil {
log.Fatalf("listen: %v", err)
}
grpcServer := grpc.NewServer()
echopb.RegisterEchoServiceServer(grpcServer, &server{})
log.Printf("Go EchoService listening on %s", addr)
if err := grpcServer.Serve(lis); err != nil {
log.Fatalf("serve: %v", err)
}
}Замечание по импортам: в зависимости от того, как именно сгенерировался пакет Go, путь может потребовать корректировки. На практике вы быстро подстроите import под фактическую структуру каталогов в echopb.
Запуск:
GRPC_ADDR=":50051" go run .Реализация сервиса на Rust (tonic)
Создадим Rust-проект:
cd ../rust-service
cargo new --bin rust-echoПерейдём в директорию проекта:
cd rust-echoДобавим зависимости в Cargo.toml:
[dependencies]
tokio = { version = "1", features = ["full"] }
tonic = { version = "0.12", features = ["transport"] }
prost = "0.12"
prost-types = "0.12"
[build-dependencies]
tonic-build = "0.12"Настроим сборку protobuf в build.rs:
use tonic_build::configure;
fn main() {
configure()
.build_server(true)
.out_dir("src/echopb")
.compile(&["../proto/echo.proto"], &["../proto"])
.unwrap();
}Подготовим src/main.rs:
pub mod echopb {
include!("echopb/echo.rs");
}
use echopb::echo_service_server::{EchoService, EchoServiceServer};
use echopb::{EchoReply, EchoRequest};
use tonic::{transport::Server, Request, Response, Status};
#[derive(Default)]
pub struct MyEcho;
#[tonic::async_trait]
impl EchoService for MyEcho {
async fn echo(&self, request: Request<EchoRequest>)
-> Result<Response<EchoReply>, Status> {
let msg = request.into_inner().message;
Ok(Response::new(EchoReply { message: msg }))
}
}
#[tokio::main]
async fn main() -> Result<<(), Box<dyn std::error::Error>>> {
let addr = std::env::var("GRPC_ADDR").unwrap_or_else(|_| ":50052".to_string());
let addr = addr.parse()?;
let svc = EchoServiceServer::new(MyEcho::default());
println!("Rust EchoService listening on {}", addr);
Server::builder()
.add_service(svc)
.serve(addr)
.await?;
Ok(())
}Запуск:
GRPC_ADDR="0.0.0.0:50052" cargo runПорты разведены, чтобы параллельно протестировать оба сервиса.
Проверка работы (gRPC curl-лайк подход или клиент)
Для gRPC в “чистом виде” нет универсального curl сценария, но можно использовать:
- тестовый gRPC клиент (например, grpcurl)
- или небольшой клиент на Go/Rust
Если нужен быстрый тест, лучше собрать маленький клиент. В рамках статьи покажем простейший подход: отдельный Go-клиент для Go-сервиса.
Сделаем файл grpc-termux/go-service/client.go:
package main
import (
"context"
"log"
"os"
"time"
"google.golang.org/grpc"
echopb "grpc-termux/go-service/echopb/echo"
)
func main() {
addr := os.Getenv("GRPC_TARGET")
if addr == "" {
addr = "127.0.0.1:50051"
}
conn, err := grpc.Dial(addr, grpc.WithInsecure(), grpc.WithBlock())
if err != nil {
log.Fatalf("dial: %v", err)
}
defer conn.Close()
c := echopb.NewEchoServiceClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), 3time.Second)
defer cancel()
resp, err := c.Echo(ctx, &echopb.EchoRequest{Message: "hello from Termux"})
if err != nil {
log.Fatalf("echo: %v", err)
}
log.Printf("response: %s", resp.GetMessage())
}Выполнить:
GRPC_TARGET="127.0.0.1:50051" go run client.goАналогично можно сделать Rust-клиент, чтобы проверить Rust-сервис на 50052.
Деплой на Termux: как сделать “службу”, а не разовый запуск
В Android/Termux запуск микросервисов — это процесс в пользовательской среде. Для удобного деплоя в рамках устройства используют следующие практики:
- запуск через скрипт entrypoint с переменными окружения
- журналирование в консоль и сохранение логов
- запуск нескольких инстансов на разных портах
- балансировка на уровне простого роутера/прокси
Скрипт запуска Go-сервиса, например run-go.sh:
#!/data/data/com.termux/files/usr/bin/sh
set -e
export GRPC_ADDR="${GRPC_ADDR:-0.0.0.0:50051}"
cd "$(dirname "$0")"
exec go run .Сделайте исполняемым:
chmod +x run-go.sh
./run-go.shДля Rust аналогично.
gRPC и protobuf: генерация как часть CI-процесса
Чтобы деплой был воспроизводимым, генерацию protobuf лучше делать при сборке:
- в Go — запуск
protocи генераторов передgo build - в Rust —
build.rs(уже встроено в cargo)
Пример для Go: добавить в сборочный скрипт шаг генерации.
#!/data/data/com.termux/files/usr/bin/sh
set -e
cd "$(dirname "$0")/.."
protoc -I ./proto --go_out=./go-service --go-grpc_out=./go-service ./proto/echo.proto
cd ./go-service
go build ./...Так вы исключаете ситуацию, когда код протокола “подтянут” вручную и забыли о несовпадениях версий.
Автоматическое масштабирование на практике: подходы для Termux
Словосочетание “автоматическое масштабирование” обычно ассоциируется с autoscaling в кластере (например, HPA/Cluster Autoscaler). В Termux на устройстве полноценная кластерная инфраструктура ограничена, но вы можете реализовать принцип — масштабирование числа инстансов сервиса под нагрузку или под очередь запросов.
Масштабирование через пул инстансов (scale-out по порту)
Суть:
- запускаем N инстансов одного сервиса на разных портах
- перед ними ставим простой балансировщик/роутер
- автоматизация N — отдельный контроллер (скрипт), который увеличивает/уменьшает число процессов
В качестве контроллера обычно используют внешний сервер. Однако на практике для прототипа на Termux можно сделать простую схему:
- оценивать нагрузку (например, по метрикам времени ответа или по числу активных задач)
- при превышении порога — запускать новый инстанс
- при снижении — завершать часть инстансов
Технически на Android ресурсы ограничены, поэтому шкалирование разумно ограничить, например максимум 2–4 инстансами.
Локальная сеть и роль VPN (только для организации сети)
Если вам нужно, чтобы устройства в одной среде могли обращаться к сервисам Termux, используйте создание локальной сети (например, при помощи VPN, предназначенного для объединения устройств в одну сеть). Это делается не для обхода блокировок, а для удобства адресации и тестирования.
Балансировка: минимальный роутинг
gRPC требует поддержки HTTP/2. Поэтому “самодельная” балансировка должна быть аккуратной. Для прототипа чаще всего используют:
- встроенный reverse proxy, поддерживающий gRPC (в “настоящем” деплой-контуре)
- либо переносите балансировку в внешний контур
На уровне Termux вы можете ограничиться масштабированием несколькими инстансами и ручной или скриптовой маршрутизацией (например, тестировать round-robin через отдельный клиент/шлюз). Для production-логики правильнее использовать внешний балансировщик.
Как деплоить в более “серверный” контур из Termux
Termux удобен для сборки. Дальше артефакты переносите в окружение, где возможен нормальный оркестратор (docker/kubernetes/VM). Практика:
- компилируете Go/Rust в Termux
- упаковываете бинарники
- передаёте в CI/CD
- разворачиваете в кластере с autoscaling
Для Rust и Go вы получите воспроизводимые артефакты, а autoscaling обеспечит инфраструктура.
Схема деплоя “под ключ” (рекомендованный цикл)
- Разработка в Termux: протоколы, серверы, клиенты
- Генерация protobuf в сборке (Go: генерация шагом; Rust: build.rs)
- Тестирование локально (localhost и локальная сеть)
- Сборка релизов (go build / cargo build --release)
- Публикация (CI/CD) и развертывание в целевом окружении
- Автоматическое масштабирование через оркестратор (HPA/metrics)
Так вы сохраняете скорость прототипирования Termux и получаете промышленный деплой.
Заключение
Termux позволяет быстро и удобно разрабатывать микросервисы на Go и Rust с gRPC и protobuf: вы определяете контракты в .proto, генерируете код, поднимаете серверы и проверяете вызовы. А идею автоматического масштабирования реализуете в два этапа: сначала — масштабирование инстансов/пулов для прототипа, затем — перенос в инфраструктуру, где autoscaling выполняется корректно и безопасно.
Если вы хотите собрать рабочий пайплайн разработки и деплоя “от proto до масштабируемого сервиса” под ваш контур, команда РыбинскЛАБ готова помочь: консультации по архитектуре, настройка сборок, gRPC/protobuf-генерация, подготовка к CI/CD и проектирование инфраструктуры масштабирования.