CLI for Dockge using Python
Find a file
Firq fc7ecdcd77
All checks were successful
/ pylint (push) Successful in 12s
/ mypy (push) Successful in 13s
Readme
2024-08-15 23:09:02 +02:00
.forgejo/workflows Fixed workflow 2 2024-07-22 17:47:06 +02:00
dockge_cli More logging 2024-07-20 17:49:25 +02:00
.gitignore Improved typing, refactored code, fixed some issues 2024-07-04 22:12:36 +02:00
Dockerfile Add docker build step to provide ready-to-use dockge cli container 2024-07-22 17:40:57 +02:00
pyproject.toml Fixed version 2024-07-22 17:42:48 +02:00
README.md Readme 2024-08-15 23:09:02 +02:00

dockge-cli

A simple CLI application written in Python for communicating with Dockge using websockets

Background

Dockge (spoken dock-ge or dockage) is a tool to manage docker-compose stacks from a web ui. It is developed by louislam, who also develops UptimeKuma.

Dockge itself doesn't offer any kind of API or programmatic access, as it is just intended for managing stacks via UI.

My current deployment solution for firq.dev and fgo-ta.com is based on Dockge, and I was over it always having to reload the stack whenever I pushed an update. Instead, I wanted to have this as a separate CI step, automatically redeploying a givens stack.

As Dockge is using a websocket-based system under the hood, it was easy to take a look at how communication occurs. In general, communication is achieved by leveraging socket.io for the data. Since Python already offers a solution for socket.io, it is just a matter of emulating the calls the webui sends and receives.

In the end, this is the current result that works pretty well for my understanding. I am still trying to improve upon some issues (login times out, stability, features), but in general this works as a fine solution for automatic stack updating.

Installation

Install it from the custom package index using

pip install --extra-index-url https://forgejo.neshweb.net/api/packages/Firq/pypi/simple/ dockge-cli

Alternativly, install it using this repository. When installing for development, make sure to install with the additional dependencies

pip install -e .[lint,typing]

Usage

Call the CLI using dockge-cli or dockge.

usage: dockge_cli [-h] [--version] {host,login,logout,list,status,restart,start,stop,down,update,exit,help}

CLI interface for interacting with Dockge

positional arguments:
  {host,login,logout,list,status,restart,start,stop,down,update,exit,help}

options:
  -h, --help            show this help message and exit
  --version             show program's version number and exit

Help for each individual command can be invoked by calling dockge-cli help <command>

The magic behind this

Generally, this makes use of the underlying Websockets API that the Dockge frontend uses to communicate with the server. By analyzing the traffic and looking into the codebase, I was able to reverse most of the packets that are being sent. This allows me to then contruct, send and receive my own packets, making the whole thing work.

There are some things that need to be taken into account for this: For one, dockge uses socket.io for the websocket communication. This meant I had to find the corresponding socket.io version to get the correct version of python-socketio. In addition, I had to find out how the authorization mechanism behind this works.

After finishing up the first prototype, the workings are as follows:

  1. A websocket session is established using socket.io - this happens automatically
  2. After the session is ready, the login command is sent together with a provided username and password
  3. Once the CLI is authorized, the selected command is sent
  4. The CLI waits for any response values and exits once the command has executed successfully

To provide a smooth experience, both the credentials and the remote host URI are stored on disk. just like the docker cli, the credentials are not encrypted, meaning it is advised to either clear the credentials after use OR to use the --username and --password parameters. This is especially recommended for CI applications.

Known issues

This CLI does not work when Mullvad is used, as Mullvad actively blocks port forwarding (which python-socketio uses)