欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

Flutter 三方库 docker2 的鸿蒙化实战 - 引入服务器与容器操作接口,高效接管 Docker 远程服务

前言

在开发 OpenHarmony 相关的运维工具、中控平台或开发者工具类应用时,经常需要与云端或局域网内的 Docker 容器进行交互(如重启服务、拉取镜像、监控容器状态)。如果直接通过 SSH 运行命令行字符串,代码将变得难以维护,且无法获得结构化的状态回执。

docker2 是一个纯 Dart 实现的 Docker Remote API 客户端库。它允许开发者直接通过 REST API 与 Docker Daemon 通信,实现对容器、镜像、网络和数据卷的精细化管控。本文将介绍如何在 OpenHarmony 应用中集成 docker2,打造移动端的容器管理终端。

一、原理剖析 / 概念介绍

1.1 核心原理

docker2 本质上是对 Docker Daemon 暴露的 RESTful API 的强类型封装。它不依赖本地的 Docker 二进制文件或 Unix Socket,而是通过标准的 HTTP/HTTPS 协议与远程主机的守护进程通信。

当开发者调用库方法时,docker2 会构建合规的 HTTP 请求发送到目标主机的 API 端口(通常是 2375 或加密的 2376)。返回的 JSON 响应会被自动解析为 Dart 对象。

网络传输 (HTTP/HTTPS)

查询引擎状态并返回 JSON

转换为强类型 Model

鸿蒙管理端 (调用 docker.containers.list)

docker2 封装请求 (GET /containers/json)

远程服务器 Docker Daemon

docker2 响应解析

UI 层展示容器列表

1.2 核心业务优势

  1. 强类型操作体验:所有的容器属性(如 ID、状态、镜像名)都映射为 Dart 类。避免了解析命令行输出时的字符串匹配错误。
  2. 零本地依赖:纯 Dart 实现,无需 FFI 链接本地 C 库,这使其在 OpenHarmony 的各种硬件架构(如 ARM64, x86_64)上具有完美的兼容性。

二、鸿蒙基础指导

2.1 适配情况

  1. 是否原生支持?:完全支持。底层使用 dart:io 的网络能力。
  2. 是否鸿蒙官方支持?:作为第三方社区库,极其适合研发 HarmonyOS 面向开发者的控制与部署工具。
  3. 是否需要额外干预?:须在 module.json5 中声明网络访问权限。

2.2 适配代码引入

将依赖添加到 pubspec.yaml

dependencies:
  docker2: ^0.1.7

三、核心 API / 组件详解

3.1 核心管理接口

方法功能说明典型代码示例
Docker(host: ...)连接句柄。指定 Docker API 的访问地址。final docker = Docker(host: 'http://ip:2375');
docker.containers.list()容器检索。获取远程主机上所有容器的状态快照。final containers = await docker.containers.list();
docker.images.create()镜像拉取。从注册表(如 Docker Hub)下载指定镜像。await docker.images.create(fromImage: 'nginx');

3.2 远程容器状态查询演示

import 'package:flutter/material.dart';

class Docker23Page extends StatelessWidget {
  const Docker23Page({super.key});
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Docker API 连接测试')),
      body: const Center(
        child: Text("通过 Docker Remote API `/containers/json` 获取列表。",
            textAlign: TextAlign.center),
      ),
    );
  }
}

四、典型应用场景

4.1 移动端 DevOps 运维控制台

运维人员可以利用 OpenHarmony 设备(如平板或手机)构建可视化运维面板。当云端服务出现报警时,无需打开笔记本电脑,直接在手持设备上通过 docker2 查看容器日志或重启故障服务,实现敏捷运维。

五、OpenHarmony 平台适配挑战

docker2 在移动端或穿戴设备上直接使用较少,其核心场景在于“开发者控制台”或“DevOps 监控器”。在项目中,建议采用 tools/ 脚本模式来封装复杂的 API 调用流。

物理隔离规范

  • 脚本路径tools/docker2/container_manager.dart
  • 应用价值:通过脚本在编译机上实现对测试镜像(如 openharmony/dev)的自动部署、状态轮询与资源清理,将 DevOps 能力内化为项目的工程支柱。

六、综合实战演示

如下在 Docker2Dashboard.dart 展示如何利用极其真实的 Docker() 实例在 Flutter 页面中监控集装箱状态:

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:docker2/docker2.dart';

class Docker2Page6 extends StatefulWidget {
  const Docker2Page6({super.key});

  
  State<Docker2Page6> createState() => _Docker2Page6State();
}

class _Docker2Page6State extends State<Docker2Page6> {
  final List<String> _logs = [];
  bool _busy = false;
  final ScrollController _scrollController = ScrollController();

  void _addLog(String msg) {
    if (!mounted) return;
    setState(() {
      _logs.add("[${DateTime.now().toString().substring(11, 19)}] $msg");
    });
    Future.delayed(const Duration(milliseconds: 50), () {
      if (_scrollController.hasClients) {
        _scrollController.animateTo(
          _scrollController.position.maxScrollExtent,
          duration: const Duration(milliseconds: 200),
          curve: Curves.easeOut,
        );
      }
    });
  }

  void _fetchStatus() async {
    setState(() {
      _busy = true;
      _logs.clear();
    });

    _addLog("➜  demo4 dart tools/docker2/container_manager.dart");
    await Future.delayed(const Duration(milliseconds: 600));
    _addLog("📡 正在枚举本地 Docker 镜像资源...");

    // 真实调用:获取镜像和容器列表
    final docker = Docker();
    try {
      final images = docker.images;
      _addLog("✅ 枚举完成: 发现 ${images.length} 个本地 Image 节点。");

      await Future.delayed(const Duration(milliseconds: 800));
      _addLog("🚢 正在列举集装箱集群 (Containers)...");

      final activeCount = docker.containers.length;
      _addLog("CONTAINER ID   NAME               STATUS");
      _addLog("--------------------------------------------------");

      for (var c in docker.containers.take(3)) {
        _addLog(
            "${c.containerId.substring(0, 8)}         ${c.imageName}     ${c.status}");
      }

      if (activeCount == 0) {
        _addLog("⚠️ 没有检测到正在运行的容器(可能是 Docker 守护进程未启动)。");
      }
    } catch (e) {
      _addLog("❌ API Error: 无法连接至 Docker 守护进程。");
      _addLog("HINT: 请确保本地已安装 Docker Desktop 并开启。");
    }

    setState(() {
      _busy = false;
    });
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: const Color(0xFF0F172A),
      appBar: AppBar(
        title: const Text('云原生集装箱仪表盘',
            style: TextStyle(
                color: Colors.white,
                fontSize: 13,
                fontWeight: FontWeight.w900,
                letterSpacing: 1.2)),
        backgroundColor: Colors.transparent,
        elevation: 0,
        iconTheme: const IconThemeData(color: Colors.white),
      ),
      body: Column(
        children: [
          Expanded(
            child: Container(
              margin: const EdgeInsets.all(16),
              padding: const EdgeInsets.all(24),
              decoration: BoxDecoration(
                color: const Color(0xFF1E293B),
                borderRadius: BorderRadius.circular(12),
                border: Border.all(color: const Color(0xFF334155)),
                boxShadow: [
                  BoxShadow(
                      color: Colors.black.withOpacity(0.3),
                      blurRadius: 20,
                      offset: const Offset(0, 10))
                ],
              ),
              child: ListView.builder(
                controller: _scrollController,
                itemCount: _logs.length,
                itemBuilder: (context, index) {
                  final log = _logs[index];
                  final isCmd = log.contains("➜");
                  return Padding(
                    padding: const EdgeInsets.only(bottom: 8.0),
                    child: Text(
                      log,
                      style: TextStyle(
                        color: isCmd
                            ? const Color(0xFF38BDF8)
                            : (log.contains("✅")
                                ? const Color(0xFF4ADE80)
                                : (log.contains("❌")
                                    ? Colors.redAccent
                                    : const Color(0xFFE2E8F0))),
                        fontFamily: 'monospace',
                        fontSize: 12,
                        height: 1.5,
                      ),
                    ),
                  );
                },
              ),
            ),
          ),
          Padding(
            padding: const EdgeInsets.fromLTRB(24, 8, 24, 32),
            child: ElevatedButton.icon(
              onPressed: _busy ? null : _fetchStatus,
              icon: _busy
                  ? const SizedBox(
                      width: 14,
                      height: 14,
                      child: CircularProgressIndicator(
                          strokeWidth: 2, color: Colors.white))
                  : const Icon(Icons.refresh_rounded),
              label: const Text("发动集装箱巡检与扩容检测",
                  style: TextStyle(
                      color: Colors.white,
                      fontWeight: FontWeight.bold,
                      letterSpacing: 1)),
              style: ElevatedButton.styleFrom(
                backgroundColor: const Color(0xFF2563EB),
                disabledBackgroundColor: const Color(0xFF334155),
                minimumSize: const Size(double.infinity, 56),
                shape: RoundedRectangleBorder(
                    borderRadius: BorderRadius.circular(16)),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

import 'package:flutter/material.dart';

class Docker2Page6 extends StatefulWidget {
  const Docker2Page6({super.key});

  
  State<Docker2Page6> createState() => _Docker2Page6State();
}

class _Docker2Page6State extends State<Docker2Page6> {
  final List<String> _logs = [];

  void _fetchStatus() async {
    setState(() {
      _logs.add("> 正在连接远程 Docker Daemon...");
    });
    // ... 模拟 API 握手
    await Future.delayed(const Duration(seconds: 1));
    setState(() {
      _logs.add("✅ 获取到 3 个容器实例:[HAP_DEV, DB, CACHE]");
    });
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('DevOps 监控台')),
      body: Column(
        children: [
          Expanded(child: ListView.builder(itemCount: _logs.length, itemBuilder: (c, i) => Text(_logs[i]))),
          ElevatedButton(onPressed: _fetchStatus, child: const Text("刷新状态"))
        ],
      ),
    );
  }
}

@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFF111827), // deep slate
appBar: AppBar(
title: const Text(‘Docker DevOps 编排中台’,
style: TextStyle(
color: Color(0xFFE5E7EB),
fontSize: 16,
fontWeight: FontWeight.bold)),
backgroundColor: Colors.transparent,
elevation: 0,
iconTheme: const IconThemeData(color: Color(0xFFE5E7EB)),
actions: [
IconButton(
icon: _isFetching
? const SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(
strokeWidth: 2, color: Color(0xFF3B82F6)))
: const Icon(Icons.sync_rounded),
onPressed: _isFetching ? null : _fetchStatus,
)
],
),
body: _containers.isEmpty && !_isFetching
? Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.dns_rounded,
size: 80, color: Color(0xFF374151)),
const SizedBox(height: 24),
const Text(“无受管接点快照”,
style: TextStyle(color: Color(0xFF6B7280), fontSize: 16)),
const SizedBox(height: 16),
ElevatedButton.icon(
onPressed: _fetchStatus,
icon: const Icon(Icons.cloud_download_rounded,
color: Colors.white),
label: const Text(“拉取内网云架构池库”,
style: TextStyle(color: Colors.white)),
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF3B82F6),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8)),
))
],
),
)
: ListView.builder(
padding: const EdgeInsets.all(20),
itemCount: _containers.length,
itemBuilder: (context, index) {
final c = _containers[index];
final isRunning = c[‘state’] == ‘running’;
return Container(
margin: const EdgeInsets.only(bottom: 16),
decoration: BoxDecoration(
color: const Color(0xFF1F2937),
borderRadius: BorderRadius.circular(16),
border: Border.all(
color: isRunning
? const Color(0xFF10B981).withOpacity(0.3)
: const Color(0xFFF43F5E).withOpacity(0.3),
width: 1),
),
child: ListTile(
contentPadding: const EdgeInsets.symmetric(
horizontal: 24, vertical: 12),
leading: Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: isRunning
? const Color(0xFF064E3B)
: const Color(0xFF4C1D95).withOpacity(0.5),
borderRadius: BorderRadius.circular(12),
),
child: Icon(
isRunning
? Icons.view_in_ar_rounded
: Icons.block_flipped,
color: isRunning
? const Color(0xFF10B981)
: const Color(0xFFF43F5E),
),
),
title: Text(c[‘name’],
style: const TextStyle(
color: Color(0xFFF9FAFB),
fontWeight: FontWeight.bold,
fontSize: 16)),
subtitle: Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Text(“Node: ${c[‘ip’]} | TCP: ${c[‘port’]}”,
style: const TextStyle(
color: Color(0xFF9CA3AF),
fontFamily: ‘monospace’,
fontSize: 11)),
),
trailing: ActionChip(
label: Text(isRunning ? “ON” : “EXIT”,
style: const TextStyle(color: Colors.white)),
backgroundColor: isRunning
? const Color(0xFF059669)
: const Color(0xFFBE123C),
side: BorderSide.none,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8)),
onPressed: () {},
),
),
);
},
),
);
}
}


## 七、总结

`docker2` 为鸿蒙应用与云端基础设施的交互提供了标准化的通道。它摆脱了传统的命令行依赖,使开发者能够利用强类型接口构建安全、高效的容器管理工具,是深耕 DevOps 领域的鸿蒙开发者不可或缺的组件。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐