commit f5a3ef47cbae99577163b5118124aea2e72edd87 Author: Sulthon Zainul Habib Date: Sat Dec 25 23:28:35 2021 +0700 init docker-remote-deployment-action diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..ecff131 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,40 @@ +name: Release + +on: + release: + types: + - created + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v1 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + + - name: Login to DockerHub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKER_HUB_USERNAME }} + password: ${{ secrets.DOCKER_HUB_PASSWORD }} + + - name: Build and push + id: docker_build + uses: docker/build-push-action@v2 + with: + context: ./ + file: ./Dockerfile + push: true + tags: | + sulthonzh/docker-remote-deployment-action:latest + sulthonzh/docker-remote-deployment-action:${{ github.event.release.tag_name }} + + + diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..805aa55 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,13 @@ +FROM docker/compose:1.29.2 + +LABEL 'name'='Docker Deployment Action' +LABEL 'com.github.actions.name'='Docker Deployment' +LABEL 'com.github.actions.description'='supports docker-compose and Docker Swarm deployments' +LABEL 'com.github.actions.icon'='send' +LABEL 'com.github.actions.color'='green' + +RUN apk --no-cache add openssh-client + +COPY docker-entrypoint.sh /docker-entrypoint.sh + +ENTRYPOINT ["/docker-entrypoint.sh"] diff --git a/action.yml b/action.yml new file mode 100644 index 0000000..38b08d4 --- /dev/null +++ b/action.yml @@ -0,0 +1,61 @@ +name: Docker Deployment +description: A GitHub Action that supports docker-compose and Docker Swarm deployments +inputs: + remote_docker_host: + description: Remote Docker host ie (user@host). + required: true + remote_docker_port: + description: Remote Docker ssh port ie (22). + required: false + default: '22' + ssh_public_key: + description: Remote Docker SSH public key eg (~/.ssh/rsa_id.pub). + required: true + ssh_private_key: + description: SSH private key used to connect to the docker host eg (~/.ssh/rsa_id). + required: true + args: + description: Deployment command args. + required: true + deployment_mode: + description: Deployment mode either docker-swarm or docker-compose. Default is docker-compose. + required: false + copy_stack_file: + description: Copy stack file to remote server and deploy from the server. Default is false. + required: false + deploy_path: + description: The path where the stack files will be copied to. Default ~/docker-deployment. + required: false + stack_file_name: + description: Docker stack file used. Default is docker-compose.yml. + required: false + keep_files: + description: Number of the files to be kept on the server. Default is 3. + required: false + docker_prune: + description: A boolean input to trigger docker prune command. Default is false. + required: false + pre_deployment_command_args: + description: The args for the pre deploument command. + required: false + pull_images_first: + description: Pull docker images before deploying. Default is false. + required: false + docker_registry_username: + description: The docker registry username. + required: false + docker_registry_password: + description: The docker registry password. + required: false + docker_registry_uri: + description: The docker registry URI. Default is https://registry.hub.docker.com. + required: false + +runs: + using: docker + image: Dockerfile + +branding: + icon: send + color: green + diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..5da503e --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,8 @@ +version: "3.3" + +services: + webapp: + image: nginx + ports: + - 8080:8080 + network_mode: bridge diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh new file mode 100755 index 0000000..94d0883 --- /dev/null +++ b/docker-entrypoint.sh @@ -0,0 +1,142 @@ +#!/bin/sh +set -eu + +execute_ssh(){ + echo "Execute Over SSH: $@" + ssh -q -t -i "$HOME/.ssh/id_rsa" \ + -o UserKnownHostsFile=/dev/null \ + -p $INPUT_REMOTE_DOCKER_PORT \ + -o StrictHostKeyChecking=no "$INPUT_REMOTE_DOCKER_HOST" "$@" +} + +if [ -z "${INPUT_REMOTE_DOCKER_PORT+x}" ]; then + INPUT_REMOTE_DOCKER_PORT=22 +fi + +if [ -z "${INPUT_REMOTE_DOCKER_HOST+x}" ]; then + echo "Input remote_docker_host is required!" + exit 1 +fi + +if [ -z "${INPUT_SSH_PUBLIC_KEY+x}" ]; then + echo "Input ssh_public_key is required!" + exit 1 +fi + +if [ -z "${INPUT_SSH_PRIVATE_KEY+x}" ]; then + echo "Input ssh_private_key is required!" + exit 1 +fi + +if [ -z "${INPUT_ARGS+x}" ]; then + echo "Input input_args is required!" + exit 1 +fi + +if [ -z "${INPUT_DEPLOY_PATH+x}" ]; then + INPUT_DEPLOY_PATH=~/docker-deployment +fi + +if [ -z "${INPUT_STACK_FILE_NAME+x}" ]; then + INPUT_STACK_FILE_NAME=docker-compose.yaml +fi + +if [ -z "${INPUT_KEEP_FILES+x}" ]; then + INPUT_KEEP_FILES=4 +else + INPUT_KEEP_FILES=$((INPUT_KEEP_FILES+1)) +fi + +if [ -z "${INPUT_DOCKER_REGISTRY_URI+x}" ]; then + INPUT_DOCKER_REGISTRY_URI=https://registry.hub.docker.com +fi + +if [ -z "${INPUT_COPY_STACK_FILE+x}" ]; then + INPUT_COPY_STACK_FILE=false +fi + +STACK_FILE=${INPUT_STACK_FILE_NAME} +DEPLOYMENT_COMMAND_OPTIONS="" + + +if [ "$INPUT_COPY_STACK_FILE" == "true" ]; then + STACK_FILE="$INPUT_DEPLOY_PATH/$STACK_FILE" +else + DEPLOYMENT_COMMAND_OPTIONS=" --log-level debug --host ssh://$INPUT_REMOTE_DOCKER_HOST:$INPUT_REMOTE_DOCKER_PORT" +fi + +case $INPUT_DEPLOYMENT_MODE in + + docker-swarm) + DEPLOYMENT_COMMAND="docker $DEPLOYMENT_COMMAND_OPTIONS stack deploy --compose-file $STACK_FILE" + ;; + + *) + INPUT_DEPLOYMENT_MODE="docker-compose" + DEPLOYMENT_COMMAND="docker-compose -f $STACK_FILE $DEPLOYMENT_COMMAND_OPTIONS" + ;; +esac + + +SSH_HOST=${INPUT_REMOTE_DOCKER_HOST#*@} + +echo "Registering SSH keys..." + +# register the private key with the agent. +mkdir -p ~/.ssh +ls ~/.ssh +printf '%s\n' "$INPUT_SSH_PRIVATE_KEY" > ~/.ssh/id_rsa +chmod 600 ~/.ssh/id_rsa +printf '%s\n' "$INPUT_SSH_PUBLIC_KEY" > ~/.ssh/id_rsa.pub +chmod 600 ~/.ssh/id_rsa.pub +#chmod 600 "~/.ssh" +eval $(ssh-agent) +ssh-add ~/.ssh/id_rsa + +echo "Add known hosts" +ssh-keyscan -p $INPUT_REMOTE_DOCKER_PORT "$SSH_HOST" >> ~/.ssh/known_hosts +ssh-keyscan -p $INPUT_REMOTE_DOCKER_PORT "$SSH_HOST" >> /etc/ssh/ssh_known_hosts + +set context +echo "Create docker context" +docker context create remote --docker "host=ssh://$INPUT_REMOTE_DOCKER_HOST:$INPUT_REMOTE_DOCKER_PORT" +docker context use remote + +if ! [ -z "${INPUT_DOCKER_REGISTRY_USERNAME+x}" ] && ! [ -z "${INPUT_DOCKER_REGISTRY_PASSWORD+x}" ]; then + echo "Connecting to $INPUT_REMOTE_DOCKER_HOST... Command: docker login" + echo "$INPUT_DOCKER_REGISTRY_PASSWORD" | docker login -u "$INPUT_DOCKER_REGISTRY_USERNAME" --password-stdin "$INPUT_DOCKER_REGISTRY_URI" +fi + +if ! [ -z "${INPUT_DOCKER_PRUNE+x}" ] && [ $INPUT_DOCKER_PRUNE = 'true' ] ; then + yes | docker --log-level debug --host "ssh://$INPUT_REMOTE_DOCKER_HOST:$INPUT_REMOTE_DOCKER_PORT" system prune -a 2>&1 +fi + +if ! [ -z "${INPUT_COPY_STACK_FILE+x}" ] && [ $INPUT_COPY_STACK_FILE = 'true' ] ; then + execute_ssh "mkdir -p $INPUT_DEPLOY_PATH/stacks || true" + FILE_NAME="docker-stack-$(date +%Y%m%d%s).yaml" + + scp -i "$HOME/.ssh/id_rsa" \ + -o UserKnownHostsFile=/dev/null \ + -o StrictHostKeyChecking=no \ + -P $INPUT_REMOTE_DOCKER_PORT \ + $INPUT_STACK_FILE_NAME "$INPUT_REMOTE_DOCKER_HOST:$INPUT_DEPLOY_PATH/stacks/$FILE_NAME" + + execute_ssh "ln -nfs $INPUT_DEPLOY_PATH/stacks/$FILE_NAME $INPUT_DEPLOY_PATH/$INPUT_STACK_FILE_NAME" + execute_ssh "ls -t $INPUT_DEPLOY_PATH/stacks/docker-stack-* 2>/dev/null | tail -n +$INPUT_KEEP_FILES | xargs rm -- 2>/dev/null || true" + + if ! [ -z "${INPUT_PULL_IMAGES_FIRST+x}" ] && [ $INPUT_PULL_IMAGES_FIRST = 'true' ] && [ $INPUT_DEPLOYMENT_MODE = 'docker-compose' ] ; then + execute_ssh ${DEPLOYMENT_COMMAND} "pull" + fi + + if ! [ -z "${INPUT_PRE_DEPLOYMENT_COMMAND_ARGS+x}" ] && [ $INPUT_DEPLOYMENT_MODE = 'docker-compose' ] ; then + execute_ssh "${DEPLOYMENT_COMMAND} $INPUT_PRE_DEPLOYMENT_COMMAND_ARGS" 2>&1 + fi + + execute_ssh ${DEPLOYMENT_COMMAND} "$INPUT_ARGS" 2>&1 +else + cat ~/.docker/config.json + echo "Connecting to $INPUT_REMOTE_DOCKER_HOST... Command: ${DEPLOYMENT_COMMAND} ${INPUT_ARGS}" + ${DEPLOYMENT_COMMAND} ${INPUT_ARGS} 2>&1 +fi + +