February 6, 2023

791 Wörter 4 Minuten

drone Automation

drone Automation

drone

Drone ist eine Continuous Integration und Continuous Deployment (CI/CD) Lösung, die es Entwicklern ermöglicht, verschiedene Dinge wie Test und Deployments von Anwendungen in einer benutzerfreundlichen Art und Weise durchzuführen.

Drone verwendet Docker-Container, um eine einheitliche und reproduzierbare “Build”-Umgebung zu gewährleisten, und bietet Plugins, um zahlreiche Integrationspunkte wie Github, Bitbucket, Gitlab und auch gitea zu unterstützen.

Drone ist Open Source und kann auf einem lokalen Rechner oder in der Cloud betrieben werden.

Beispiel: hello-world

---
kind: pipeline
type: docker
name: hello-world

steps:
  - name: say-hello
    image: busybox
    commands:
      - echo hello-world

Installation Server & Runner

Ich nutze drone auf einem virtuellen Server. Dort habe ich die beiden erforderlichen docker Container mit Hilfe eines docker-compose.yml Datei erstellt.

HINWEIS Dieses Beispiel benötigt ein konfiguriertes traefik

---
version: '3.8'

services:
  drone-server:
    container_name: drone
    image: drone/drone:${DRONE_VERSION:-2.16}
    restart: unless-stopped
    environment:
      # https://docs.drone.io/server/provider/gitea/
      - DRONE_DATABASE_DRIVER=sqlite3
      - DRONE_DATABASE_DATASOURCE=/data/database.sqlite
      - DRONE_GITEA_SERVER=https://git.bueraner.de/
      - DRONE_GIT_ALWAYS_AUTH=false
      - DRONE_RPC_SECRET=${DRONE_RPC_SECRET}
      - DRONE_SERVER_PROTO=https
      - DRONE_SERVER_HOST=ci.bueraner.de
      - DRONE_TLS_AUTOCERT=false
      - DRONE_USER_CREATE=${DRONE_USER_CREATE}
      - DRONE_GITEA_CLIENT_ID=${DRONE_GITEA_CLIENT_ID}
      - DRONE_GITEA_CLIENT_SECRET=${DRONE_GITEA_CLIENT_SECRET}
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.drone.rule=Host(`ci.bueraner.de`)"
    networks:
      - traefik_web
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./drone:/data

  drone-runner:
    container_name: drone-runner
    image: drone/drone-runner-docker:${DRONE_RUNNER_VERSION:-1}
    restart: unless-stopped
    depends_on:
      drone-server:
        condition: service_started
    environment:
      # https://docs.drone.io/runner/docker/installation/linux/
      # https://docs.drone.io/server/metrics/
      - DRONE_RPC_PROTO=https
      - DRONE_RPC_HOST=ci.bueraner.de
      - DRONE_RPC_SECRET=${DRONE_RPC_SECRET}
      - DRONE_RUNNER_NAME="${HOSTNAME}-runner"
      - DRONE_RUNNER_CAPACITY=2
      - DRONE_RUNNER_NETWORKS=traefik_web
      - DRONE_DEBUG=false
      - DRONE_TRACE=false
    networks:
      - traefik_web
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
networks:
  traefik_web:
    external: true

Desweiteren müsst ihr noch einen RPC key mittels

openssl rand -hex 24

Kommando erstellen und die Applikation mittels Oauth in gitea registrieren. Details dazu findet ihr unter https://containers.fan/posts/setup-drone-server-and-drone-runner-for-gitea-on-docker/

Use-case: Statische Webseite

Um den Workflow mit meiner statischen Webseite zu vereinfachen, habe ich mir benutzerdefinierte docker image gebaut, welches auf alpine basiert. Auch dieses Image wird durch drone erstellt und in die gitea Package-Registry übertragen.

.drone.yml

Die Pipeline Definition befindet sich standardmäßig im root-Verzeichnis des entsprechenen gitea Repos. Hier mein Beispiel welches ich zum Aktualisieren der kirchhoffs.de Seite verwende.

---
kind: pipeline
name: default

steps:
  - name: Build & Deploy
    image: git.bueraner.de/murdoc/docker-hugo:latest
    environment:
      LFTP_PASSWORD:
        from_secret: kirchhoffs_password
      LFTP_USER:
        from_secret: kirchhoffs_username
      LFTP_HOST:
        from_secret: kirchhoffs_hostname
    commands:
      - hugo version
      - hugo
      - LCD="$(pwd)/public"
      - chmod -R 755 "$LCD"
      - RCD="/hugo"
      - lftp --env-password sftp://"$LFTP_USER@$LFTP_HOST" \
        -e "set sftp:auto-confirm yes;set ftp:list-options -a; \
        mirror --continue --reverse --delete --verbose $LCD $RCD; bye"

  - name: notify
    group: post
    image: drillster/drone-email
    settings:
      from.address:
        from_secret: email_from
      host:
        from_secret: email_host
      username:
        from_secret: email_username
      password:
        from_secret: email_password
      recipients:
        from_secret: email_recipients
      subject: >
        [{{ build.status }}]
        {{ repo.owner }}/{{ repo.name }}
        ({{ build.branch }} - {{ truncate build.commit 8 }})        
    when:
      status:
        - changed
        - failure

Sobald ich nun einen Artikel in das Repo sende, läuft automatisch die Pipeline los, rendert mittels hugo Kommando die Seite und synchronsiert die Seite auf meinem Webspace. Hier sei noch erwähnt das rsync auch eine Synchronisation ermöglicht, allerdings habe ich bei meinem Webspace Provider “nur” einen SFTP Zugang. Das oben genannte Image enthält aber auch das rsync Paket.

Das verwendete docker image besteht aus einem Alpine Distro mit ein paar zusätzlichen Programmen. Anbei exemplarisch das dockerfile:

FROM alpine:3.17

LABEL org.opencontainers.image.authors="murdoc@storm-clan.de" \
      org.label-schema.name="Hugo image" \
      org.label-schema.vendor="murdoc" \
      org.label-schema.schema-version="0.1.0"

ENV CURL_VERSION="7.87.0-r1"
ENV GIT_VERSION="2.38.3-r1"
ENV GO_VERSION="1.19.5-r0"
ENV BASH_VERSION="5.2.15-r0"
ENV BASH_COMPLETION_VERSION="2.11-r4"
ENV LFTP_VERSION="4.9.2-r4"
ENV RSYNC_VERSION="3.2.7-r0"
ENV OPENSSH_VERSION="9.1_p1-r2"

RUN apk add --no-cache \
    curl="$CURL_VERSION" \
    git="$GIT_VERSION" \
    go="$GO_VERSION"  \
    bash="$BASH_VERSION" \
    bash-completion="$BASH_COMPLETION_VERSION" \
    lftp="$LFTP_VERSION" \
    rsync="$RSYNC_VERSION" \
    openssh-client="$OPENSSH_VERSION" \
  && rm -rf /var/cache/apk/*

ENV HUGO_VERSION=0.110.0
SHELL ["/bin/bash", "-o", "pipefail", "-c"]

RUN mkdir -p /usr/local/src
WORKDIR /usr/local/src

RUN curl -L https://github.com/gohugoio/hugo/releases/download/\
    v${HUGO_VERSION}/hugo_${HUGO_VERSION}_Linux-64bit.tar.gz | tar -xz \
    && mv hugo /usr/local/bin/hugo \
    && addgroup -Sg 1000 hugo \
    && adduser -SG hugo -u 1000 -h /src hugo

WORKDIR /src

EXPOSE 1313

Deployment

Die Pipeline startet automatisch nachdem die Änderungen mittels git push ins Repo übermittelt werden.

Plugins

Am Beispiel unter .drone.yml zu sehen ist, kann man mit drone auch eine Vielzahl von Plugins verwerden. In dem Beispiel nutze ich das drone-email Plugin um mich informieren zu lassen, falls beim “deployment” etwas schief geht.

Übersicht drone Plugins

Cron Jobs

Es können auch regelmäßige Aufgaben geplant und zeitlich automatisch durch drone gestartet werden. Dazu gibt es die folenden Intervalle:

  • @hourly
  • @daily
  • @weekly
  • @monthly
  • @yearly

Badges

Badges sind kleine Übersichtsgrafiken die über den Zustand der Pipeline Aufschluss geben. In drone ist momentan nur der aktuelle Build Status einzusehen. Weitere Infos könnnen aber mit Zusatzdiensten implemementiert werden.

Installation drone-cli

Ein cooles Feature von drone, das man die pipeline auch seinem lokalen Rechner testen kann. Das spart Zeit beim entwickeln, da man nicht immer auf die Remote Pipeline warten muss. Die Installation ist schnell abgeschlossen unter ArchLinux mittels folgendem Kommando:

sudo pacman -S drone-cli

Mittels dem Kommando

drone exec

Kann die Pipeline gestartet werden. Sofern die interne “Secrets”-Verwaltung genutzt werden, kann man sich eine lokale Datei mit den Secrets erstellen und es beim Aufruf mit angeben.

drone exec --secret-file=.env