Skip to content

Instantly share code, notes, and snippets.

@lightningspirit
Last active March 25, 2024 16:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lightningspirit/dd7baff0ab94e7f776e08bfae34ea697 to your computer and use it in GitHub Desktop.
Save lightningspirit/dd7baff0ab94e7f776e08bfae34ea697 to your computer and use it in GitHub Desktop.
Docker Client Plugin to SSH Remote Docker Hosts

Docker Client Plugin to SSH Remote Docker Hosts

Configuration for each project using a simple YAML file. The docker remote command reads the relative local file docker-remote.yml to access docker hosts. Uses SSH under the hood.

Examples of usage

Showing remote running containers

Implicit user parameter

docker remote remote-hostname ps

Using root as user

docker remote root@remote-hostname ps

docker-remote.yml

version: "1"

remotes:
  - name: remote-hostname
    host: 10.20.30.40
    user: root
    private_key:
      file: ~/.ssh/id_rsa

Required parameters

The only required parameters are name and host. Both user and private_key can be omitted to use default system values.

If user is omitted, it will SSH with your local logged in user (like any other SSH connection). You can override it directly using the user@host format (i.e. desired_user@remote-hostname).

#!/bin/bash
# Docker Client Plugin to SSH Remote Docker Hosts
#
# (c) 2024 lightningspirit
# lightningspirit@gmail.com
# https://lightningspir.it
#
# Usage:
# docker remote [remote-hostname] [OPTIONS] COMMAND
#
set -e
if [[ "$1" == "docker-cli-plugin-metadata" ]]; then
cat <<EOF
{
"SchemaVersion": "0.1.0",
"Vendor": "lightningspirit",
"Version": "0.2.1",
"ShortDescription": "Docker Client Plugin to SSH Remote Docker Hosts"
}
EOF
exit
fi
# default docker remote yaml file
DOCKER_REMOTE_FILE="${DOCKER_REMOTE_FILE:-docker-remote.yml}"
usage() {
cat <<EOF
Usage: docker remote [remote-hostname] [OPTIONS] COMMAND
Docker Client Plugin to Access Remote Docker Hosts
Use any docker option and command.
See docker --help for further info.
EOF
}
shift
# split user and host
REMOTE=$(echo $1 |tr "@" "\n")
# read user if variable has two lines (first line is user)
if [ "$(echo "$REMOTE" | wc -l | sed 's/^[[:space:]]*//')" -eq 2 ]; then
read -r SSH_USER <<< "$REMOTE"
fi
REMOTE=$(echo "$REMOTE" | tail -n 1)
COMMAND="${@:2}"
shift
if [ -z "$REMOTE" ]; then
usage
exit 0
fi
if [ -z "$COMMAND" ] || [ "$COMMAND" == "-h" ] || [ "$COMMAND" == "--help" ]; then
usage
exit 0
fi
function install_cmd {
case `uname -s` in
Linux )
which -s yum && { echo "yum install yq"; return; }
which -s apt && { echo "apt install yq"; return; }
which -s snap && { echo "snap install yq"; return; }
;;
Darwin )
which -s brew && { echo "brew install yq"; return; }
;;
* )
echo "visit https://github.com/mikefarah/yq"; return;
;;
esac
}
# make sure yq is installed
if ! command -v yq &> /dev/null
then
cat <<EOF
Error: Dependency 'yq' is missing.
$(install_cmd)
EOF
exit 1
fi
# retrieve all variables
export $(yq e '.remotes.[] | select(.name == "'$REMOTE'") | .. | (
select(kind == "scalar" and parent | kind != "seq") | (
path | .[2:] | join("_") | upcase
) + "=" + .
)' ./$DOCKER_REMOTE_FILE) > /dev/null
if [ -z "$HOST" ]; then
echo "Error: $REMOTE not found in $DOCKER_REMOTE_FILE"
exit 0
fi
if [ $PRIVATE_KEY_FILE ]; then
# handle tilde (~) if exists
EXPANDED_KEY_FILE="${PRIVATE_KEY_FILE/#\~/$HOME}"
# check key presence otherwise load
ssh-add -l | grep -q `ssh-keygen -lf $EXPANDED_KEY_FILE | awk '{print $2}'` || ssh-add $EXPANDED_KEY_FILE
fi
# connect to host
docker --host "ssh://${SSH_USER:-$USER}@$HOST" $COMMAND
exit 0
version: "1"
remotes:
- name: remote-hostname
host: 10.20.30.40
user: root
private_key:
file: ~/.ssh/id_rsa
{
"$schema": "https://json-schema.org/draft/2019-09/schema#",
"id": "remote_spec.json",
"type": "object",
"title": "Remote Specification",
"description": "The Remote file is a YAML file defining a multi-remotes.",
"properties": {
"version": {
"type": "string",
"description": "declared for backward compatibility, ignored."
},
"remotes": {
"id": "#/properties/remotes",
"type": "array",
"items": {
"$ref": "#/definitions/remote"
}
}
},
"additionalProperties": false,
"definitions": {
"remote": {
"id": "#/definitions/remote",
"type": "object",
"properties": {
"name": {
"type": "string"
},
"host": {
"type": "string"
},
"user": {
"type": "string"
},
"private_key": {
"$ref": "#/definitions/private_key"
}
},
"required": ["name", "host"]
},
"private_key": {
"id": "#/definitions/private_key",
"type": "object",
"properties": {
"file": {
"type": "string"
}
},
"additionalProperties": false
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment