Day eight: deploying
All checks were successful
Build and copy to prod / build-and-copy (push) Successful in 1m57s
All checks were successful
Build and copy to prod / build-and-copy (push) Successful in 1m57s
This commit is contained in:
parent
1b1c3e6636
commit
2c4187a0df
145
src/blog/posts/2024/5/learning-go-day-8.md
Normal file
145
src/blog/posts/2024/5/learning-go-day-8.md
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
---
|
||||||
|
title: "Learning Go: Day Eight"
|
||||||
|
date: 2024-05-08T08:00:00.0Z
|
||||||
|
tags:
|
||||||
|
- learning
|
||||||
|
- go
|
||||||
|
excerpt: "Getting the project deployed via Gitea actions"
|
||||||
|
---
|
||||||
|
|
||||||
|
So that I can do the whole build-in-public thing properly, I always want my code to automatically deploy. I've got [Gitea Actions](https://docs.gitea.com/usage/actions/overview) on my Gitea server, so I can use those to build, deploy, and start a Go binary.
|
||||||
|
|
||||||
|
## Building and copying a binary
|
||||||
|
|
||||||
|
This is the simplest part. I had a decent template from my Eleventy action that I was able to take and turn into the following workflow:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
name: Build and copy to prod
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
jobs:
|
||||||
|
build-and-copy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- name: Setup Go
|
||||||
|
uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version: 1.22
|
||||||
|
- name: Build binary
|
||||||
|
run: go build -o dist/oopsie
|
||||||
|
- name: Install SSH Key
|
||||||
|
uses: shimataro/ssh-key-action@v2
|
||||||
|
with:
|
||||||
|
key: ${{ secrets.SSH_KEY }}
|
||||||
|
known_hosts: ${{ secrets.SSH_KNOWN_HOSTS }}
|
||||||
|
- name: Copy to prod
|
||||||
|
run: scp -rp dist/* ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}:oopsie/
|
||||||
|
```
|
||||||
|
|
||||||
|
This installs Go on the action runner, builds the binary, and then uses SCP to copy the compiled binary onto my server. To facilitate this, I created a user on my VPS, created a new SSH key, and added the public key to the `.ssh/authorized_keys` file. Then I added the private key to the Gitea action secrets, along with the `known_hosts` entry for my git server, the name of the user I created, and the hostname for my VPS.
|
||||||
|
|
||||||
|
## Running the software
|
||||||
|
|
||||||
|
So now I need to run my compiled software. I can create a systemd service to do this, and then run it as the user I've created. First of all I create a new file, `/etc/systemd/user/oopsie.service`:
|
||||||
|
|
||||||
|
```systemd
|
||||||
|
[Unit]
|
||||||
|
Description=Daemon for the Oopsie service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
#User=
|
||||||
|
#Group=
|
||||||
|
ExecStart=/home/<user>/oopsie/oopsie
|
||||||
|
Restart=on-failure
|
||||||
|
StandardOutput=file:%h/log_file
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, as the user I've created I run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
systemctl --user daemon-reload
|
||||||
|
systemctl --user start oopsie.service
|
||||||
|
```
|
||||||
|
|
||||||
|
And can confirm my service is running locally:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST http://localhost:8000
|
||||||
|
> This was a POST request!
|
||||||
|
```
|
||||||
|
|
||||||
|
## Nginx proxy
|
||||||
|
|
||||||
|
Next up I need to use Nginx's `proxy_pass` directive to direct any requests to https://oopsie.lewisdale.dev to my running service. Again, this was mostly lifted from an existing template I already had:
|
||||||
|
|
||||||
|
```nginx
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
listen [::]:80;
|
||||||
|
server_name oopsie.lewisdale.dev;
|
||||||
|
rewrite ^ https://$server_name$request_uri? permanent;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
# SSL configuration
|
||||||
|
#
|
||||||
|
listen 443 ssl;
|
||||||
|
listen [::]:443 ssl;
|
||||||
|
server_name oopsie.lewisdale.dev;
|
||||||
|
|
||||||
|
# Include certificate params
|
||||||
|
include snippets/certs/lewisdale.dev;
|
||||||
|
ssl_certificate /etc/letsencrypt/live/lewisdale.dev/fullchain.pem; # managed by Certbot
|
||||||
|
ssl_certificate_key /etc/letsencrypt/live/lewisdale.dev/privkey.pem; # managed by Certbot
|
||||||
|
|
||||||
|
include /etc/letsencrypt/options-ssl-nginx.conf;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://localhost:8000;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Woo, now I can actually access my service over the internet!
|
||||||
|
|
||||||
|
![Screenshot from Mozilla Firefox, showing oopsie.lewisdale.dev responding with "This was a GET request!"](./src/images/oopsie-working.png)
|
||||||
|
|
||||||
|
## Restarting the service
|
||||||
|
|
||||||
|
Finally, I can use the `-o` argument with the `RemoteCommand` [SSH config option](https://linux.die.net/man/5/ssh_config) to execute a command. I can use that to run `systemctl restart`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- name: Restart the service
|
||||||
|
run: ssh ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} -o RemoteCommand="systemctl --user restart oopsie.service"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Nope
|
||||||
|
|
||||||
|
Ah, that's not quite correct. My first build failed:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scp: oopsie//oopsie: Text file busy
|
||||||
|
```
|
||||||
|
|
||||||
|
I can't overwrite a file while it's in use. Instead, I have to stop the service, copy the file, and then start the service again:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- name: Stop the service
|
||||||
|
run: ssh ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} -o RemoteCommand="systemctl --user stop oopsie.service"
|
||||||
|
- name: Copy to prod
|
||||||
|
run: scp -rp dist/* ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}:oopsie/
|
||||||
|
- name: Restart the service
|
||||||
|
run: ssh ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} -o RemoteCommand="systemctl --user start oopsie.service"
|
||||||
|
```
|
||||||
|
|
||||||
|
And that works! It deploys successfully. Ironically, there's a minor bit of downtime while it does, but for now that's really not an issue. You can see the project in progress on [its deployed home](https://oopsie.lewisdale.dev) or [on the Git repo](https://git.lewisdale.dev/lewis/oopsie).
|
BIN
src/images/oopsie-working.png
Normal file
BIN
src/images/oopsie-working.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
Loading…
Reference in New Issue
Block a user