Closed rafsaf closed 3 years ago
That's out of the scope of this repo, which exists solely to publish a Docker image for webhook.
Just to share what I've done;
root
so things like permissions need to be accounted for.sh
(shell) so I can execute commands/scripts (it does not include bash
)With those expectations, my mentality is for my execute-command
to be a shell script that checks if any of the commands I plan to use exist, and if not it installs them. Check and then install is useful because it will check and install when the first webhook request is received after creating the container, but not reinstall every time a webhook is received.
My docker-compose.yml
services:
webhook:
image: ghcr.io/thecatlady/webhook:latest
container_name: webhook
command: -verbose -hooks=hooks.json -hotreload
volumes:
- /etc/localtime:/etc/localtime:ro
- /path/to/config:/config:ro
- /path/to/parent/git_folder:/opt/git
- /path/to/.ssh:/root/.ssh:ro
ports:
- 9000:9000
restart: unless-stopped
In the above:
/path/to/config
is hopefully self explanatory/path/to/parent/git_folder
is one level above where I put all my git repos (ex: /home/myuser/git/
which contains multiple repos), you can mount your git repos however works for you (it's not really relevant to answering this issue)/path/to/.ssh
for me is /home/myuser/.ssh
which contains my id_ed25519
(deploy key for github) (again, not really relevant to answering this issue)My hooks.json
(placed at /path/to/config/hooks.json
)
[
{
"id": "my-hook-name",
"execute-command": "/config/run/git-checkout-force.sh",
"command-working-directory": "/opt/git/myrepo",
"include-command-output-in-response": true,
"include-command-output-in-response-on-error": true,
"pass-arguments-to-command": [
{ "source": "payload", "name": "head_commit.id", "comment": "GIT_REF" },
{
"source": "string",
"name": "/opt/git/myrepo",
"comment": "GIT_DIR"
},
{ "source": "string", "name": "1000", "comment": "PUID" },
{ "source": "string", "name": "1000", "comment": "PGID" }
],
"trigger-rule": {
"and": [
{
"match": {
"type": "payload-hmac-sha1",
"secret": "<YOUR_GITHUB_WEBHOOK_SECRET>",
"parameter": { "source": "header", "name": "X-Hub-Signature" }
}
},
{
"match": {
"type": "value",
"value": "refs/heads/main",
"parameter": { "source": "payload", "name": "ref" }
}
}
]
}
}
]
I'm not going to go too much into the details of this, it's all covered in https://github.com/adnanh/webhook/tree/master/docs
I will note that I'm expecting the branch to be main
, you might need it to be master
or something else.
Also, command-working-directory
is pointed at where the container will see my repo folder (mounted inside the container).
My git-checkout-force.sh
(placed at /path/to/config/run/git-checkout-force.sh
)
#!/usr/bin/env sh
# variables
GIT_REF=${1}
GIT_DIR=${2}
PUID=${3}
PGID=${4}
# log date
date
# install git
if ! command -v git > /dev/null 2>&1; then
apk add --no-cache \
git
fi
# install openssh
if ! command -v ssh > /dev/null 2>&1; then
apk add --no-cache \
openssh
fi
# allow git with different ownership
git config --global --add safe.directory ${GIT_DIR}
# fetch from git
git fetch --all
# checkout git reference
git checkout --force ${GIT_REF}
# set ownership
chown -R ${PUID}:${PGID} ${GIT_DIR}
In the above:
GIT_REF
is the first argument, passed in when webhook
runs the script. It should be the commit id (see hooks.json above
)PUID
and PGID
are the second/third arguments, passed in, later used to chown
. Why not hard code? So I can setup multiple hooks with the end result allowing different file ownership in each working directory.git
command exists. If not, install it using apk
(the alpine package manager included in the base OS of the image)ssh
command exists. If not, install itgit config --global --add safe.directory ${GIT_DIR}
newer versions of git
started caring about who owns the files in the repository, so tell git
this directory is safe to run the rest of the commands (since root
is the user running webhook
in the container). This can result in root
being the owner of newly added or changed files, which we will handle belowgit fetch --all
self explanatorygit checkout --force ${GIT_REF}
force checkout the referenced commit (passed in argument)chown -R ${PUID}:${PGID} ${GIT_DIR}
set the ownership of all the files in the repo using the PUID
and PGID
that are passed to the script from hooks.json
The important takeaways:
webhook
runs in the container as rootwebhook
executes via your hooks.json
execute as rootchown
at the end of your script so that root
is not the owner of your filesgit
or ssh
) but you can install the tools you need in your scriptThe image itself does not need to change. It just requires some clever configuration. It may be reasonable to document some of this information in the README.
The image itself does not need to change. It just requires some clever configuration. It may be reasonable to document some of this information in the README.
@nemchik Thanks for the writeup! Feel free to submit a PR to update the README. 🙂
Hi, this is a nice image, i would love to use it instead of hard coding webhook directly on server's OS, BUT there is a problem you didn't mentioned in README and I suppose it makes the image at least not useful in many cases and at worst not useful at all for some situations.
This was discussed in more detail here for example: https://stackoverflow.com/questions/32163955/how-to-run-shell-script-on-host-from-docker-container
Short: If you want to execute shell scripts from the inside of a container, you need to use hacks or even worse hacks (this is not designed this way, but the opposite), and after doing so, encounter problems like container restart, server restart which may (or may not) mess up things, in sense of messing those hacks. I didn't find yet any clean and STABLE solution to this problem (disclaimer: didn't spend much time trying), you probably don't want to run your scripts inside of the container with Webhook (which actually happens by reasonable default after using this image), but directly in OS, and this is different matter.
To sum up (it's late nigh here in PL :D, hope above text is understandable), if you are aware of any clean and stable solution, please share, cheers ;)