Aim: Write a simple flask app that can be hosted on the pi such that a new commit pushed from the laptop sees the pi update the site.
Context: I want to play with microcontrollers. However, I work from a laptop and tend to move rooms quite frequently. I don’t want cables dangling around.
It’s feasible to develop over ssh, but it’s suboptimal. What would be better is:
Write on a laptop -> send to a pi and build -> flash to microcontroller
(I don’t think I care how long the builds take. Maybe I will?)
Thought this was a good first step towards this goal + I get a local server.
Setting up the remote (pi)
On the pi (pipipipi - cos I was feeling particularly inspired when naming it)
git init --bare ~/sandpit/fast-deploy.git
On the laptop
git remote add deploy ssh://pipipipi/~/sandpit/fast-deploy.git
Post receive hook
This is the hook executed when a push is received. It needs to check if the push is on the “deploy” branch, and if so execute some script.
Hooks are not tracked.
So adding a hook on the laptop (ie writing the content to .git/hooks/post-receive
and setting the mode chmod +755 .git/hooks/post-receive
) and git pushing to pi, won’t see this hook reaching the pi.
Given that this is a key part that I wish to iterate on, I really want this automated.
One work around is to symlink the post receive hook to a tracked file. However, the remote is a bare repository: the files are not transparently available. Setting up a non-bare repository would have the problem that the pushed branch will be checked out on the remote, and git will complain.
A first source
#!/bin/bash
TARGET="/home/pi/sandpit/fast-deploy"
GIT_DIR="/home/webuser/fast-deploy.git"
BRANCH="deploy"
while read oldrev newrev ref
do
# only checking out the master (or whatever branch you would like to deploy)
if [ "$ref" = "refs/heads/$BRANCH" ];
then
echo "Ref $ref received. Deploying ${BRANCH} branch to production..."
git --work-tree=$TARGET --git-dir=$GIT_DIR checkout -f $BRANCH
else
echo "Ref $ref received. Doing nothing: only the ${BRANCH} branch may be deployed on this server."
fi
done
Someone else had a similar question. Putting these two together, let’s try the following.
Set the post-receive hook on the remote to
#!/bin/bash
GIT_WORK_TREE=~/sandpit/fast-deploy.git
export GIT_WORK_TREE
read oldrev newrev ref
git show deploy:post-receive.sh | bash -s -- $ref
(with mode set to executable) and put a modified version of the instructions in a file post-receive.sh
at the root of the project.
The post-receive script looks at the ref.
If the deploy
branch is updated, then it copies the content of the repo into another directory, and from here executes deploy.sh
.
An nginx uwsgi flask trio
Now to deploy something we can easily see.
I took the tutorial as a starting point, but hit quite a few errors. (Surely me not the tutorial?)
Ensure packages are installed on the pi:
sudo apt update
sudo apt install python3-pip python3-dev build-essential libssl-dev libffi-dev python3-setuptools
Both my laptop and pi are running versions of python3.7 so there shouldn’t be issues here.
Set up a barebones flask+uwsgi project.
The deploy.sh
script to act as the entry point.
The deploy script handles:
- activating the venv
- installing/updating python packages
- restarting the wsgi service
The deploy script does not attempt the initial set-up of wsgi + nginx services. It didn’t seem worth the effort automating this bit too.
uwsgi service on the pi
Adding a wsgi service for the project.
In /etc/systemd/system/fast-deploy.service
, write
[Unit]
Description=uWSGI instance to serve myproject
After=network.target
[Service]
User=pi
Group=pi
WorkingDirectory=/home/pi/sandpit/fast-deploy
Environment="PATH=/home/pi/sandpit/fast-deploy/venv/bin"
ExecStart=/home/pi/sandpit/fast-deploy/venv/bin/uwsgi --ini wsgi.ini
[Install]
WantedBy=multi-user.target
To start the service and ensure it restarts on subsequent boots:
sudo systemctl start fast-deploy.service
sudo systemctl enable fast-deploy.service
nginx service on the pi
Install nginx. I think this is launched with
sudo /etc/init.d/nginx start
(But I’d done this previously.)
The config files are located in /etc/nginx
.
From here, add the config file for the particular project in
/etc/nginx/sites-available/flask_demo.conf
.
server {
listen 80;
server_name 10.100.74.22;
charset utf-8;
location / {
include uwsgi_params;
uwsgi_pass 127.0.0.1:3031;
}
}
Note 10.100.74.22
is the server name of the pi.
A symlink is added then to enable the available site:
sudo ln -s /etc/nginx/sites-available/flask_demo.conf /etc/nginx/sites-enabled/
Next steps
- kiwipi build for accelerometer.
- pipipipi build for microcontroller
- add pre-push tests and update requirements