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.gitOn the laptop
git remote add deploy ssh://pipipipi/~/sandpit/fast-deploy.gitPost 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
doneSomeone 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-setuptoolsBoth 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.targetTo start the service and ensure it restarts on subsequent boots:
sudo systemctl start fast-deploy.service
sudo systemctl enable fast-deploy.servicenginx 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