1. Introduction
  2. Setting up an example Pipeline
    1. Setting Up a Simple Node.js App
    2. Setting Up Drone Pipeline
  3. Resources

Introduction

In my previous post I went over how to set up a server on Linode and how to install Drone on that server. Today we’ll be going over what Drone Pipelines are and how to set up a simple pipeline.

Drone Pipelines are very versatile. There are variety of Runners that can deal with different pipelines. The one we installed last week is a Docker Runner. This lets us use all the Docker images available to set up our building/testing environment. In a real world pipeline, you would probably have a combination of building, testing, and deploying.

Pipelines are configured through a .drone.yml file where you specify the steps and configurations you want to use. In this post, we will create a simple Node.js app and configure the pipeline to automatically deploy the app upon committing to the git repository.

Setting Up An Example Pipeline

Setting Up a Simple Node.js App

To make a pipeline, you’ll need to already have a server set up and Drone installed. I went over this in my last post in case you missed it. Let’s start by connecting to the server:

ssh username@drone.yourdomain.com

Remember to use your username and domain you set up. Next, we’ll need to install Node.js so that Node apps can actually run on the server:

sudo snap install node --channel=14/stable --classic

You can check to see if Node.js was installed correctly by checking for its version:

node -v

This should display something like v14.x.x depending on the version you installed. Now let’s create a new folder to house our app:

mkdir /usr/bin/node_app/
touch /usr/bin/node_app/app.js

To put content into our app, let’s open it up and edit it:

vim ~/node_app/app.js

Hit i, and type in the following:

#!/usr/bin/env node
const http = require('http')
const port = 3001

const requestHandler = (request, response) => {
  response.end('Simple Node App')
}

const server = http.createServer(requestHandler)

server.listen(port)

Hit esc and type in :wq to save and exit. This is a simple app that listens to the port 3000 over http and returns the text Simple Node App. The top line indicates that when we run this file, we want to use Node.

Now we have to expose the app by setting up a reverse proxy with NGINX. We can do this by editing the NGINX file we set up for the Drone Server.

sudo vim /etc/nginx/sites-enabled/drone.conf

Hit i to start editing. We can specify a specific path on drone.yourdomain.com to point to our reverse proxy. Inset the following after the location / server block:

  location /app {
      proxy_pass http://localhost:3001/;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection upgrade;
      proxy_set_header Accept-Encoding gzip;
  }

This passes all requests made to drone.yourdomain.com/app to http://localhost:3001/ which is where our app will be listening on. We can test the configuration to make sure it it valid before we enable it:

sudo nginx -t

This should return a test is successful message. Now let’s enable the configuration by restarting NGINX:

sudo systemctl restart nginx

We can now test out our app to make sure it runs correctly:

chmod +x ~/node_app/app.js
~/node_app/app.js

This will leave the console hanging, but you should be able to go to drone.yourdomain.com/app and see the message Simple Node App!

Now, let’s set up a linux service to keep our app running in the background. Type Ctrl + c in the terminal to exit out of the app. Let’s start by creating the service file:

mkdir -p ~/.config/systemd/user
touch ~/.config/systemd/usernode_app.service
vim ~/.config/systemd/user/node_app.service

Hit i to start editing and enter the following:

[Unit]
Description=App

[Service]
ExecStart=/home/username/node_app/app.js
Restart=always

[Install]
WantedBy=multi-user.target

Make sure to replace username with the actual user name of the user on the server. Now we can enable and start the app:

sudo systemctl --user enable node_app.service
sudo systemctl --user start node_app.service
sudo loginctl enable-linger username

Again, remember to replace username with the actual Linux username you are using. This set up is a little different from above because we are setting up the service as a user service, and not a system wide service. The enable-linger command let’s the user be logged in at all times so that the service can run.

Now the Node.js app is successfully deployed! You can double check by going to drone.yourdomain.com/app and making sure the message is still loading. The next step is to automatically deploy any changes we make to the app with Drone.

Setting Up Drone Pipeline

The first step is to set up a git repository for our app. On Gitea, go to the upper right hand corner and click New Repository. Fill out the information and click Create Repository. You don’t have to make the repository private, I was just lazy and left it on the default.

Create Git Repo

Next, we want to set up our git details and go into the folder where we put our app to initialize a git repository and push it to our Gitea server:

git config --global user.email "you@example.com"
git config --global user.name "Your Name"
cd ~/node_app/
touch README.md
git init
git add .
git commit -m "First commit"
git remote add origin https://git.yourdomain.com/gitusername/node_app.git
git push -u origin master

Remember to replace the email, name, and url with your own. Now you can go on your Gitea page and see your committed files!

Everything is committed!

Now, we can start building the pipeline. To begin, create and open the .drone.yml file:

touch ~/node_app/.drone.yml
vim ~/node_app/.drone.yml

We’ll need to add in all the steps that we need to deploy the app. We want Drone to get the updated app.js, upload it to the server, and restart the Linux service. Hit i to start editing and insert the following:

kind: pipeline
type: docker
name: default

steps:
- name: upload
  image: appleboy/drone-scp
  settings:
    host:
      from_secret: ssh_host
    user:
      from_secret: ssh_user
    key:
      from_secret: ssh_key
    passphrase:
      from_secret: ssh_password
    port: 22
    target:
      from_secret: ssh_target
    source: app.js

- name: restart_service
  image: appleboy/drone-ssh
  settings:
    host:
      from_secret: ssh_host
    user:
      from_secret: ssh_user
    key:
      from_secret: ssh_key
    passphrase:
      from_secret: ssh_password
    port: 22
    script:
    - systemctl --user restart node_app.service

trigger:
  branch:
  - master
  event:
  - push

Hit esc and type :wq to save and quit. You might notice that there are a bunch of secrets in the .yml file. These are the parameters that are needed to connect to your server, you don’t want these viewable to the public, so you can configure these secrets in Drone. This lets you also upload your pipeline to public git repositories.

The .drone.yml file above defines two steps in the pipeline. The first step is to upload the app.js file to the server, and the second step is to restart the service we created to deploy our app. The triggers tell Drone to only deploy the new file if there is a push to the master branch.

Now that our pipeline is defined, we can go to our Drone server to finish setting it up. Go to drone.yourdomain.com and activate the repository you just created. If you don’t see it, you can click the sync button to reload repositories. After you activate the repository on Drone, you will be taken to the settings page.

Pipeline Settings

Once here, you’ll need to configure the SCP/SSH secrets for our pipelines to pull from. Lets first generate the SSH keys:

ssh-keygen

This will prompt you to use a passphrase, we’ll also need to put this passphrase into Drone as a secret. Add the following secrets:

  1. ssh_host: drone.yourdomain.com
  2. ssh_user: username
  3. ssh_key: output from ~/.ssh/id_rsa
  4. ssh_password: passphrase used to create ssh key
  5. ssh_target: /home/username/node_app/

In a real world scenario, you probably wouldn’t want to use your drone server as your production server, but we’re throwing everyone on a single server in this example. To get the output from ~/.ssh/id_rsa you can run this command:

cat ~/.ssh/id_rsa

Next, we want to configure our server so that the Drone server can SSH/SCP into the server:

sudo vim ~/.ssh/authorized_keys

Hit i and go to the end of the file and hit Enter to start a new line and then paste your SSH public key. Hit esc and type :wq to save and exit. You can find your public key in ~/.ssh/id_rsa.pub. You can test your connection by connecting to your server yourself:

ssh username@drone.yourdomain.com

In this case you’re connecting to the server from the server so it’s kind of weird, but you should still be able to connect. Once you have your secrets and keys configured, you can go ahead and commit the file to automatically deploy the app. It’s kind of weird in this case, since we’re pushing it from the server to deploy it on the server, but at this point you could pull the git repository onto another computer and commit. Let’s alter the text that is displayed in order to make sure our deploy worked as intended:

vim ~/node_app/app.js

Hit i to start editing and change the message to anything you want. Then, hit esc and type :wq to save and exit. Now let’s try committing and pushing our altered app:

cd ~/node_app/
git add .
git commit -m "Testing deployment"
git push

If you go to your Drone server and the activity is stuck at pending, we need to restart our Drone Runner:

sudo systemctl restart drone-runner.service

Drone should automatically have deployed your altered app! If you go to drone.yourdomain.com/app it should now be the altered text. You can see the successful deployment on Drone:

Successfully Deployed!

Resources

  1. Drone SCP Plugin (http://plugins.drone.io/appleboy/drone-scp/)
  2. Drone SSH Plugin (http://plugins.drone.io/appleboy/drone-ssh/)