These are a set of workflows for a very early stage development-production
environment using docker containers.
It heavily relies on gbili/git-server-hooks
which is a simple git server with a post-receive
hook (or any other hook you would like to add to it for that matter) in charge of deploying the new code to some directory readable by the production application container.
This production application container can for example be based on node-app-js
or node-app-ts
etc.
Production application container
In order to present the application to the user, these containers need to somehow get the main application code from the developer's machine.
A few ways can be used:
- get the code from the development machine prepacking it with a Dockerfile build
- git push the code to the production host, and somehow let the running container use the newly pushed code
Option 1: Packaging the code with docker build
The more standard way, seems to be the option 1. It requires:
Independently:
- git add
- git commit
- git push
Once version controlled, we need to:
- In dev machine
docker build
(probably only rebuilding the last layers) - In dev machine
docker push
- In host machine
docker-compose restart
There are ways to link both parts, with client git-hooks
post-commit
for example.
Why not use this way then ? Big question left unanswered. Especially if there is no limitation in creating a script to do the whole thing in a single command.
Option 2: Git Pushing to a running container
In this approach we rely on git-server-hooks
container. It's a simple Git server for a single user.
And another to fix permissions on the shared volume. In order to deploy the pushed git code to the running app container, we need to make sure that we give the proper permissions to the running app container. And it should be easy except it seems git
determines what rights should be attributed to the checkedout
code, and they are very few.
Node: So we use a different strategy, which makes sure every X seconds that the app directory that git just checked out to, has the proper permissions for node to run the app.
Then again, even after fixing the permissions to make the new deployed code accessible to the app, we still need to have a way to npm i
and restart the app.
Node: Since we need to restart anyway, this additional container, does not even need to exist if the permissions are fixed at docker-compose restart
by the real app's start.sh
script.
Note: that there is a nuance on whether we are serving a static contents or not. If the content is static, there would be no need to restart the container because the new static content would frictionlessly be made available.
All in all it requires these steps:
- git add
- git commit
- git push
Once version controlled:
- In host machine
docker-compose restart
With this setup we are able to skip the docker image build/push/pull
cycle. Of course if the image was big, it could be an advantage. But for most it does seem more of a trouble than an advancement.
We used option 2
One would wonder why stick with option 2 when we have determined that the first is the standard, plus the second requires gymnastics using root on an entry point script ect. Which are known bad practices.
But we do bad decisions... So here is the workflow anyway.
- Make sure to have a
git-server-hooks
container running and accessible at some url. And with your ssh keys - Create a repository for the application on the server's
git-server-hooks
:- for that use
git-server-hooks-repo-add
'sdocker-compose.yml
adjusted to the new repo docker-compose up
that to create the temporary container that will create the repo
- for that use
- In the development machine, configure the git repo to push to the new host remote
git commit -am "feat: new amazing thing"
andgit push live master
- This will push the code and deploy it to the
git-server-hooks_node-server
volume - Get an image of
node-app-js
in the host machine, and configure it to serve the app using:nginx-proxy
network for the domain to be ssledgit-server-hooks_node-server
's volume as the app's root directory where the git deployed code andpackage.json
are and wherenpm i
can be run
docker-compose up
ordocker-compose restart
after git pushing to thelive
remote.- Use the
dotfiles
/git-pushup -d <docker-compose.yml's_dir>
in order to push the code to git and the production volume and immediately restart the container.- This will use
docker-restart-service
script on the host to restart the proper service living in the-d
dir
- This will use
- Use the
These are the initial steps, but once you have everything setup, every commit requires you to do a simple git-pushup -d myapp_dir
in order to update the app's container.
How would it look like using option 1
We could combine the already existing dotfiles
's script docker-build-push -t <remote/tag:num>
to get it triggered after a git push
and add a flush-start
to remove the old image and rebuild. But deleting the images from the registry and then pulling will take some time. Then, we would have the advantage of being able to add some ci
in the Dockerfile
. We would no longer need to use an entry point which is a shell script (even though we run it using exec to make it first PID).