Administration articles moved

This commit is contained in:
Laszlo Fogas 2019-11-13 19:50:54 +01:00
parent 64a241ccc8
commit a63a74053e
22 changed files with 474 additions and 593 deletions

186
README.md
View file

@ -20,13 +20,6 @@ An opinionated fork of the Drone CI system.
- [Pipeline documentation](#pipeline-documentation)
- [Plugins](#plugins)
- [Custom plugins](#custom-plugins)
- [Server setup](#server-setup)
- [Quickstart](#quickstart)
- [Authentication](#authentication)
- [Database](#database)
- [SSL](#ssl)
- [Metrics](#metrics)
- [Behind a proxy](#behind-a-proxy)
- [Contributing](#contributing)
- [License](#license)
@ -133,185 +126,6 @@ Plugins are Docker containers with their entrypoint set to a predefined script.
## Server setup
#### Quickstart
The below [docker-compose](https://docs.docker.com/compose/) configuration can be used to start the Drone server with a single agent. It relies on a number of environment variables that you must set before running `docker-compose up`. The variables are described below.
Each agent is able to process one build by default. If you have 4 agents installed and connected to the Drone server, your system will process 4 builds in parallel. You can add more agents to increase the number of parallel builds or set the agent's `DRONE_MAX_PROCS=1` environment variable to increase the number of parallel builds for that agent.
```yaml
version: '2'
services:
drone-server:
image: drone/drone:{{% version %}}
ports:
- 80:8000
- 9000
volumes:
- drone-server-data:/var/lib/drone/
restart: always
environment:
- DRONE_OPEN=true
- DRONE_HOST=${DRONE_HOST}
- DRONE_GITHUB=true
- DRONE_GITHUB_CLIENT=${DRONE_GITHUB_CLIENT}
- DRONE_GITHUB_SECRET=${DRONE_GITHUB_SECRET}
- DRONE_SECRET=${DRONE_SECRET}
drone-agent:
image: drone/agent:{{% version %}}
command: agent
restart: always
depends_on:
- drone-server
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
- DRONE_SERVER=drone-server:9000
- DRONE_SECRET=${DRONE_SECRET}
volumes:
drone-server-data:
```
Drone needs to know its own address. You must therefore provide the address in `<scheme>://<hostname>` format. Please omit trailing slashes.
```diff
services:
drone-server:
image: drone/drone:{{% version %}}
environment:
- DRONE_OPEN=true
+ - DRONE_HOST=${DRONE_HOST}
- DRONE_GITHUB=true
- DRONE_GITHUB_CLIENT=${DRONE_GITHUB_CLIENT}
- DRONE_GITHUB_SECRET=${DRONE_GITHUB_SECRET}
- DRONE_SECRET=${DRONE_SECRET}
```
Drone agents require access to the host machine Docker daemon.
```diff
services:
drone-agent:
image: drone/agent:{{% version %}}
command: agent
restart: always
depends_on: [ drone-server ]
+ volumes:
+ - /var/run/docker.sock:/var/run/docker.sock
```
Drone agents require the server address for agent-to-server communication.
```diff
services:
drone-agent:
image: drone/agent:{{% version %}}
command: agent
restart: always
depends_on: [ drone-server ]
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
+ - DRONE_SERVER=drone-server:9000
- DRONE_SECRET=${DRONE_SECRET}
```
Drone server and agents use a shared secret to authenticate communication. This should be a random string of your choosing and should be kept private. You can generate such string with `openssl rand -hex 32`.
```diff
services:
drone-server:
image: drone/drone:{{% version %}}
environment:
- DRONE_OPEN=true
- DRONE_HOST=${DRONE_HOST}
- DRONE_GITHUB=true
- DRONE_GITHUB_CLIENT=${DRONE_GITHUB_CLIENT}
- DRONE_GITHUB_SECRET=${DRONE_GITHUB_SECRET}
+ - DRONE_SECRET=${DRONE_SECRET}
drone-agent:
image: drone/agent:{{% version %}}
environment:
- DRONE_SERVER=drone-server:9000
- DRONE_DEBUG=true
+ - DRONE_SECRET=${DRONE_SECRET}
```
Drone registration is closed by default. This example enables open registration for users that are members of approved GitHub organizations.
```diff
services:
drone-server:
image: drone/drone:{{% version %}}
environment:
+ - DRONE_OPEN=true
+ - DRONE_ORGS=dolores,dogpatch
- DRONE_HOST=${DRONE_HOST}
- DRONE_GITHUB=true
- DRONE_GITHUB_CLIENT=${DRONE_GITHUB_CLIENT}
- DRONE_GITHUB_SECRET=${DRONE_GITHUB_SECRET}
- DRONE_SECRET=${DRONE_SECRET}
```
Drone administrators should also be enumerated in your configuration.
```diff
services:
drone-server:
image: drone/drone:{{% version %}}
environment:
- DRONE_OPEN=true
- DRONE_ORGS=dolores,dogpatch
+ - DRONE_ADMIN=johnsmith,janedoe
- DRONE_HOST=${DRONE_HOST}
- DRONE_GITHUB=true
- DRONE_GITHUB_CLIENT=${DRONE_GITHUB_CLIENT}
- DRONE_GITHUB_SECRET=${DRONE_GITHUB_SECRET}
- DRONE_SECRET=${DRONE_SECRET}
```
#### Authentication
Authentication is done using OAuth and is delegated to one of multiple version control providers, configured using environment variables. The example above demonstrates basic GitHub integration.
See the complete reference for [Github](docs/administration/github.md), [Bitbucket Cloud](docs/administration/bitbucket.md), [Bitbucket Server](docs/administration/bitbucket_server.md) and [Gitlab](docs/administration/gitlab.md).
#### Database
Drone mounts a [data volume](https://docs.docker.com/storage/volumes/#create-and-manage-volumes) to persist the sqlite database.
See the [database settings](docs/administration/database.md) page to configure Postgresql or MySQL as database.
```diff
services:
drone-server:
image: drone/drone:{{% version %}}
ports:
- 80:8000
- 9000
+ volumes:
+ - drone-server-data:/var/lib/drone/
restart: always
```
#### SSL
Drone supports ssl configuration by mounting certificates into your container.
See the [SSL guide](docs/administration/ssl.md).
Automated [Lets Encrypt](docs/administration/lets_encrypt.md) is also supported.
#### Metrics
A [Prometheus endpoint](docs/administration/lets_encrypt.md) is exposed.
#### Behind a proxy
See the [proxy guide](docs/administration/proxy.md) if you want to see a setup behind Apache, Nginx, Caddy or ngrok.
## Contributing

View file

@ -1,48 +0,0 @@
This guide provides instructions for using alternate storage engines. Please note this is optional. The default storage engine is an embedded SQLite database which requires zero installation or configuration.
# Configure MySQL
The below example demonstrates mysql database configuration. See the official driver [documentation](https://github.com/go-sql-driver/mysql#dsn-data-source-name) for configuration options and examples.
```diff
version: '2'
services:
drone-server:
image: drone/drone:{{% version %}}
environment:
+ DRONE_DATABASE_DRIVER: mysql
+ DRONE_DATABASE_DATASOURCE: root:password@tcp(1.2.3.4:3306)/drone?parseTime=true
```
# Configure Postgres
The below example demonstrates postgres database configuration. See the official driver [documentation](https://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNSTRING) for configuration options and examples.
```diff
version: '2'
services:
drone-server:
image: drone/drone:{{% version %}}
environment:
+ DRONE_DATABASE_DRIVER: postgres
+ DRONE_DATABASE_DATASOURCE: postgres://root:password@1.2.3.4:5432/postgres?sslmode=disable
```
# Database Creation
Drone does not create your database automatically. If you are using the mysql or postgres driver you will need to manually create your database using `CREATE DATABASE`
# Database Migration
Drone automatically handles database migration, including the initial creation of tables and indexes. New versions of Drone will automatically upgrade the database unless otherwise specified in the release notes.
# Database Backups
Drone does not perform database backups. This should be handled by separate third party tools provided by your database vendor of choice.
# Database Archiving
Drone does not perform data archival; it considered out-of-scope for the project. Drone is rather conservative with the amount of data it stores, however, you should expect the database logs to grow the size of your database considerably.

View file

@ -1,38 +0,0 @@
Drone supports automated ssl configuration and updates using let's encrypt. You can enable let's encrypt by making the following modifications to your server configuration:
```diff
services:
drone-server:
image: drone/drone:{{% version %}}
ports:
+ - 80:80
+ - 443:443
- 9000:9000
volumes:
- /var/lib/drone:/var/lib/drone/
restart: always
environment:
- DRONE_OPEN=true
- DRONE_HOST=${DRONE_HOST}
- DRONE_GITHUB=true
- DRONE_GITHUB_CLIENT=${DRONE_GITHUB_CLIENT}
- DRONE_GITHUB_SECRET=${DRONE_GITHUB_SECRET}
- DRONE_SECRET=${DRONE_SECRET}
+ - DRONE_LETS_ENCRYPT=true
```
Note that Drone uses the hostname from the `DRONE_HOST` environment variable when requesting certificates. For example, if `DRONE_HOST=https://foo.com` the certificate is requested for `foo.com`.
>Once enabled you can visit your website at both the http and the https address
# Certificate Cache
Drone writes the certificates to the below directory:
```
/var/lib/drone/golang-autocert
```
# Certificate Updates
Drone uses the official Go acme library which will handle certificate upgrades. There should be no addition configuration or management required.

View file

@ -1,162 +0,0 @@
Drone is compatible with Prometheus and exposes a `/metrics` endpoint. Please note that access to the metrics endpoint is restricted and requires an authorization token with administrative privileges.
```nohighlight
global:
scrape_interval: 60s
scrape_configs:
- job_name: 'drone'
bearer_token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
static_configs:
- targets: ['drone.domain.com']
```
# Authorization
An administrator will need to generate a user api token and configure in the prometheus configuration file as a bearer token. Please see the following example:
```diff
global:
scrape_interval: 60s
scrape_configs:
- job_name: 'drone'
+ bearer_token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
static_configs:
- targets: ['drone.domain.com']
```
# Metric Reference
List of prometheus metrics specific to Drone:
```
# HELP drone_build_count Total number of builds.
# TYPE drone_build_count gauge
drone_build_count 7275
# HELP drone_pending_jobs Total number of pending build processes.
# TYPE drone_pending_jobs gauge
drone_pending_jobs 0
# HELP drone_repo_count Total number of registered repositories.
# TYPE drone_repo_count gauge
drone_repo_count 133
# HELP drone_running_jobs Total number of running build processes.
# TYPE drone_running_jobs gauge
drone_running_jobs 0
# HELP drone_user_count Total number of active users.
# TYPE drone_user_count gauge
drone_user_count 15
```
List of prometheus metrics for server resource usage:
```
# HELP go_gc_duration_seconds A summary of the GC invocation durations.
# TYPE go_gc_duration_seconds summary
go_gc_duration_seconds{quantile="0"} 0.000189189
go_gc_duration_seconds{quantile="0.25"} 0.000391444
go_gc_duration_seconds{quantile="0.5"} 0.001895967
go_gc_duration_seconds{quantile="0.75"} 0.003075854
go_gc_duration_seconds{quantile="1"} 0.004224575
go_gc_duration_seconds_sum 0.019922696
go_gc_duration_seconds_count 10
# HELP go_goroutines Number of goroutines that currently exist.
# TYPE go_goroutines gauge
go_goroutines 24
# HELP go_memstats_alloc_bytes Number of bytes allocated and still in use.
# TYPE go_memstats_alloc_bytes gauge
go_memstats_alloc_bytes 2.556344e+06
# HELP go_memstats_alloc_bytes_total Total number of bytes allocated, even if freed.
# TYPE go_memstats_alloc_bytes_total counter
go_memstats_alloc_bytes_total 2.0479656e+07
# HELP go_memstats_buck_hash_sys_bytes Number of bytes used by the profiling bucket hash table.
# TYPE go_memstats_buck_hash_sys_bytes gauge
go_memstats_buck_hash_sys_bytes 1.45144e+06
# HELP go_memstats_frees_total Total number of frees.
# TYPE go_memstats_frees_total counter
go_memstats_frees_total 200332
# HELP go_memstats_gc_cpu_fraction The fraction of this program's available CPU time used by the GC since the program started.
# TYPE go_memstats_gc_cpu_fraction gauge
go_memstats_gc_cpu_fraction 8.821705133777562e-05
# HELP go_memstats_gc_sys_bytes Number of bytes used for garbage collection system metadata.
# TYPE go_memstats_gc_sys_bytes gauge
go_memstats_gc_sys_bytes 557056
# HELP go_memstats_heap_alloc_bytes Number of heap bytes allocated and still in use.
# TYPE go_memstats_heap_alloc_bytes gauge
go_memstats_heap_alloc_bytes 2.556344e+06
# HELP go_memstats_heap_idle_bytes Number of heap bytes waiting to be used.
# TYPE go_memstats_heap_idle_bytes gauge
go_memstats_heap_idle_bytes 3.842048e+06
# HELP go_memstats_heap_inuse_bytes Number of heap bytes that are in use.
# TYPE go_memstats_heap_inuse_bytes gauge
go_memstats_heap_inuse_bytes 4.972544e+06
# HELP go_memstats_heap_objects Number of allocated objects.
# TYPE go_memstats_heap_objects gauge
go_memstats_heap_objects 19986
# HELP go_memstats_heap_released_bytes Number of heap bytes released to OS.
# TYPE go_memstats_heap_released_bytes gauge
go_memstats_heap_released_bytes 0
# HELP go_memstats_heap_sys_bytes Number of heap bytes obtained from system.
# TYPE go_memstats_heap_sys_bytes gauge
go_memstats_heap_sys_bytes 8.814592e+06
# HELP go_memstats_last_gc_time_seconds Number of seconds since 1970 of last garbage collection.
# TYPE go_memstats_last_gc_time_seconds gauge
go_memstats_last_gc_time_seconds 1.4941783810383117e+09
# HELP go_memstats_lookups_total Total number of pointer lookups.
# TYPE go_memstats_lookups_total counter
go_memstats_lookups_total 325
# HELP go_memstats_mallocs_total Total number of mallocs.
# TYPE go_memstats_mallocs_total counter
go_memstats_mallocs_total 220318
# HELP go_memstats_mcache_inuse_bytes Number of bytes in use by mcache structures.
# TYPE go_memstats_mcache_inuse_bytes gauge
go_memstats_mcache_inuse_bytes 2400
# HELP go_memstats_mcache_sys_bytes Number of bytes used for mcache structures obtained from system.
# TYPE go_memstats_mcache_sys_bytes gauge
go_memstats_mcache_sys_bytes 16384
# HELP go_memstats_mspan_inuse_bytes Number of bytes in use by mspan structures.
# TYPE go_memstats_mspan_inuse_bytes gauge
go_memstats_mspan_inuse_bytes 81016
# HELP go_memstats_mspan_sys_bytes Number of bytes used for mspan structures obtained from system.
# TYPE go_memstats_mspan_sys_bytes gauge
go_memstats_mspan_sys_bytes 98304
# HELP go_memstats_next_gc_bytes Number of heap bytes when next garbage collection will take place.
# TYPE go_memstats_next_gc_bytes gauge
go_memstats_next_gc_bytes 4.819216e+06
# HELP go_memstats_other_sys_bytes Number of bytes used for other system allocations.
# TYPE go_memstats_other_sys_bytes gauge
go_memstats_other_sys_bytes 672584
# HELP go_memstats_stack_inuse_bytes Number of bytes in use by the stack allocator.
# TYPE go_memstats_stack_inuse_bytes gauge
go_memstats_stack_inuse_bytes 622592
# HELP go_memstats_stack_sys_bytes Number of bytes obtained from system for stack allocator.
# TYPE go_memstats_stack_sys_bytes gauge
go_memstats_stack_sys_bytes 622592
# HELP go_memstats_sys_bytes Number of bytes obtained from system.
# TYPE go_memstats_sys_bytes gauge
go_memstats_sys_bytes 1.2232952e+07
# HELP go_threads Number of OS threads created
# TYPE go_threads gauge
go_threads 9
# HELP process_cpu_seconds_total Total user and system CPU time spent in seconds.
# TYPE process_cpu_seconds_total counter
process_cpu_seconds_total 0.9
# HELP process_max_fds Maximum number of open file descriptors.
# TYPE process_max_fds gauge
process_max_fds 524288
# HELP process_open_fds Number of open file descriptors.
# TYPE process_open_fds gauge
process_open_fds 17
# HELP process_resident_memory_bytes Resident memory size in bytes.
# TYPE process_resident_memory_bytes gauge
process_resident_memory_bytes 2.5296896e+07
# HELP process_start_time_seconds Start time of the process since unix epoch in seconds.
# TYPE process_start_time_seconds gauge
process_start_time_seconds 1.494177893e+09
# HELP process_virtual_memory_bytes Virtual memory size in bytes.
# TYPE process_virtual_memory_bytes gauge
process_virtual_memory_bytes 4.23243776e+08
```

View file

@ -1,11 +1,13 @@
Drone comes with built-in support for Bitbucket Cloud. To enable Bitbucket Cloud you should configure the Drone container using the following environment variables:
# Bitbucket
Woodpecker comes with built-in support for Bitbucket Cloud. To enable Bitbucket Cloud you should configure the Woodpecker container using the following environment variables:
```diff
version: '2'
version: '3'
services:
drone-server:
image: drone/drone:{{% version %}}
woodpecker-server:
image: laszlocloud/woodpecker-server:v0.9.0
ports:
- 80:8000
- 9000
@ -20,19 +22,19 @@ services:
+ - DRONE_BITBUCKET_SECRET=30f5064039e6b359e075
- DRONE_SECRET=${DRONE_SECRET}
drone-agent:
image: drone/agent:{{% version %}}
woodpecker-agent:
image: laszlocloud/woodpecker-agent:v0.9.0
restart: always
depends_on:
- drone-server
- woodpecker-server
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
- DRONE_SERVER=drone-server:9000
- DRONE_SERVER=woodpecker-server:9000
- DRONE_SECRET=${DRONE_SECRET}
```
# Configuration
## Configuration
This is a full list of configuration options. Please note that many of these options use default configuration values that should work for the majority of installations.
@ -45,7 +47,7 @@ DRONE_BITBUCKET_CLIENT
DRONE_BITBUCKET_SECRET
: Bitbucket oauth2 client secret
# Registration
## Registration
You must register your application with Bitbucket in order to generate a client and secret. Navigate to your account settings and choose OAuth from the menu, and click Add Consumer.
@ -65,6 +67,6 @@ Repositories:Read
Webhooks:Read and Write
```
# Missing Features
## Missing Features
Merge requests are not currently supported. We are interested in patches to include this functionality. If you are interested in contributing to Drone and submitting a patch please [contact us](https://discourse.drone.io).
Merge requests are not currently supported. We are interested in patches to include this functionality. If you are interested in contributing to Woodpecker and submitting a patch please [contact us](https://discourse.drone.io).

View file

@ -1,11 +1,13 @@
Drone comes with experimental support for Bitbucket Server, formerly known as Atlassian Stash. To enable Bitbucket Server you should configure the Drone container using the following environment variables:
# Bitbucket Server
Woodpecker comes with experimental support for Bitbucket Server, formerly known as Atlassian Stash. To enable Bitbucket Server you should configure the Woodpecker container using the following environment variables:
```diff
version: '2'
version: '3'
services:
drone-server:
image: drone/drone:{{% version %}}
woodpecker-server:
image: laszlocloud/woodpecker-server:v0.9.0
ports:
- 80:8000
- 9000
@ -25,19 +27,19 @@ services:
volumes:
+ - /path/to/key.pem:/path/to/key.pem
drone-agent:
image: drone/agent:{{% version %}}
woodpecker-agent:
image: laszlocloud/woodpecker-agent:v0.9.0
restart: always
depends_on:
- drone-server
- woodpecker-server
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
- DRONE_SERVER=drone-server:9000
- DRONE_SERVER=woodpecker-server:9000
- DRONE_SECRET=${DRONE_SECRET}
```
# Private Key File
## Private Key File
The OAuth process in Bitbucket server requires a private and a public RSA certificate. This is how you create the private RSA certificate.
@ -51,16 +53,16 @@ This stores the private RSA certificate in `key.pem`. The next command generates
openssl rsa -in /etc/bitbucket/key.pem -pubout >> /etc/bitbucket/key.pub
```
Please note that the private key file can be mounted into your Drone conatiner at runtime or as an environment variable
Please note that the private key file can be mounted into your Woodpecker conatiner at runtime or as an environment variable
Private key file mounted into your Drone container at runtime as a volume.
Private key file mounted into your Woodpecker container at runtime as a volume.
```diff
version: '2'
services:
drone-server:
image: drone/drone:{{% version %}}
woodpecker-server:
image: laszlocloud/woodpecker-server:v0.9.0
environment:
- DRONE_OPEN=true
- DRONE_HOST=${DRONE_HOST}
@ -78,11 +80,11 @@ services:
Private key as environment variable
```diff
version: '2'
version: '3'
services:
drone-server:
image: drone/drone:{{% version %}}
woodpecker-server:
image: laszlocloud/woodpecker-server:v0.9.0
environment:
- DRONE_OPEN=true
- DRONE_HOST=${DRONE_HOST}
@ -95,18 +97,18 @@ services:
- DRONE_SECRET=${DRONE_SECRET}
```
# Service Account
## Service Account
Drone uses `git+https` to clone repositories, however, Bitbucket Server does not currently support cloning repositories with oauth token. To work around this limitation, you must create a service account and provide the username and password to Drone. This service account will be used to authenticate and clone private repositories.
Woodpecker uses `git+https` to clone repositories, however, Bitbucket Server does not currently support cloning repositories with oauth token. To work around this limitation, you must create a service account and provide the username and password to Woodpecker. This service account will be used to authenticate and clone private repositories.
# Registration
## Registration
You must register your application with Bitbucket Server in order to generate a consumer key. Navigate to your account settings and choose Applications from the menu, and click Register new application. Now copy & paste the text value from `/etc/bitbucket/key.pub` into the `Public Key` in the incoming link part of the application registration.
Please use http://drone.mycompany.com/authorize as the Authorization callback URL.
# Configuration
## Configuration
This is a full list of configuration options. Please note that many of these options use default configuration values that should work for the majority of installations.

View file

@ -0,0 +1,49 @@
# Databases
This guide provides instructions for using alternate storage engines. Please note this is optional. The default storage engine is an embedded SQLite database which requires zero installation or configuration.
## Configure MySQL
The below example demonstrates mysql database configuration. See the official driver [documentation](https://github.com/go-sql-driver/mysql#dsn-data-source-name) for configuration options and examples.
```diff
version: '3'
services:
woodpecker-server:
image: laszlocloud/woodpecker-server:v0.9.0
environment:
+ DRONE_DATABASE_DRIVER: mysql
+ DRONE_DATABASE_DATASOURCE: root:password@tcp(1.2.3.4:3306)/drone?parseTime=true
```
## Configure Postgres
The below example demonstrates postgres database configuration. See the official driver [documentation](https://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNSTRING) for configuration options and examples.
```diff
version: '3'
services:
woodpecker-server:
image: laszlocloud/woodpecker-server:v0.9.0
environment:
+ DRONE_DATABASE_DRIVER: postgres
+ DRONE_DATABASE_DATASOURCE: postgres://root:password@1.2.3.4:5432/postgres?sslmode=disable
```
## Database Creation
Woodpecker does not create your database automatically. If you are using the mysql or postgres driver you will need to manually create your database using `CREATE DATABASE`
## Database Migration
Woodpecker automatically handles database migration, including the initial creation of tables and indexes. New versions of Woodpecker will automatically upgrade the database unless otherwise specified in the release notes.
## Database Backups
Woodpecker does not perform database backups. This should be handled by separate third party tools provided by your database vendor of choice.
## Database Archiving
Woodpecker does not perform data archival; it considered out-of-scope for the project. Woodpecker is rather conservative with the amount of data it stores, however, you should expect the database logs to grow the size of your database considerably.

View file

@ -1,11 +1,13 @@
Drone comes with built-in support for GitHub and GitHub Enterprise. To enable GitHub you should configure the Drone container using the following environment variables:
# Github
Woodpecker comes with built-in support for GitHub and GitHub Enterprise. To enable GitHub you should configure the Woodpecker container using the following environment variables:
```diff
version: '2'
version: '3'
services:
drone-server:
image: drone/drone:{{% version %}}
woodpecker-server:
image: laszlocloud/woodpecker-server:v0.9.0
ports:
- 80:8000
- 9000
@ -20,19 +22,19 @@ services:
+ - DRONE_GITHUB_SECRET=${DRONE_GITHUB_SECRET}
- DRONE_SECRET=${DRONE_SECRET}
drone-agent:
image: drone/agent:{{% version %}}
woodpecker-agent:
image: laszlocloud/woodpecker-agent:v0.9.0
restart: always
depends_on:
- drone-server
- woodpecker-server
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
- DRONE_SERVER=drone-server:9000
- DRONE_SERVER=woodpecker-server:9000
- DRONE_SECRET=${DRONE_SECRET}
```
# Registration
## Registration
Register your application with GitHub to create your client id and secret. It is very import the authorization callback URL matches your http(s) scheme and hostname exactly with `<scheme>://<host>/authorize` as the path.
@ -40,7 +42,7 @@ Please use this screenshot for reference:
![github oauth setup](github_oauth.png)
# Configuration
## Configuration
This is a full list of configuration options. Please note that many of these options use default configuration values that should work for the majority of installations.

View file

Before

Width:  |  Height:  |  Size: 154 KiB

After

Width:  |  Height:  |  Size: 154 KiB

View file

@ -1,11 +1,13 @@
Drone comes with built-in support for the GitLab version 8.2 and higher. To enable GitLab you should configure the Drone container using the following environment variables:
# Gitlab
Woodpecker comes with built-in support for the GitLab version 8.2 and higher. To enable GitLab you should configure the Woodpecker container using the following environment variables:
```diff
version: '2'
services:
drone-server:
image: drone/drone:{{% version %}}
woodpecker-server:
image: laszlocloud/woodpecker-server:v0.9.0
ports:
- 80:8000
- 9000
@ -19,19 +21,19 @@ services:
+ - DRONE_GITLAB_URL=http://gitlab.mycompany.com
- DRONE_SECRET=${DRONE_SECRET}
drone-agent:
image: drone/agent:{{% version %}}
woodpecker-agent:
image: laszlocloud/woodpecker-agent:v0.9.0
restart: always
depends_on:
- drone-server
- woodpecker-server
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
- DRONE_SERVER=drone-server:9000
- DRONE_SERVER=woodpecker-server:9000
- DRONE_SECRET=${DRONE_SECRET}
```
# Configuration
## Configuration
This is a full list of configuration options. Please note that many of these options use default configuration values that should work for the majority of installations.
@ -59,8 +61,8 @@ DRONE_GITLAB_SKIP_VERIFY=false
DRONE_GITLAB_PRIVATE_MODE=false
: Set to true if GitLab is running in private mode.
# Registration
## Registration
You must register your application with GitLab in order to generate a Client and Secret. Navigate to your account settings and choose Applications from the menu, and click New Application.
Please use `http://drone.mycompany.com/authorize` as the Authorization callback URL. Grant `api` scope to the application.
Please use `http://woodpecker.mycompany.com/authorize` as the Authorization callback URL. Grant `api` scope to the application.

View file

@ -0,0 +1,42 @@
# Let's Encrypt
Woodpecker supports automated SSL configuration and updates using Let's Encrypt.
You can enable Let's Encrypt by making the following modifications to your server configuration:
```diff
services:
woodpecker-server:
image: laszlocloud/woodpecker-server:v0.9.0
ports:
+ - 80:80
+ - 443:443
- 9000:9000
volumes:
- /var/lib/drone:/var/lib/drone/
restart: always
environment:
- DRONE_OPEN=true
- DRONE_HOST=${DRONE_HOST}
- DRONE_GITHUB=true
- DRONE_GITHUB_CLIENT=${DRONE_GITHUB_CLIENT}
- DRONE_GITHUB_SECRET=${DRONE_GITHUB_SECRET}
- DRONE_SECRET=${DRONE_SECRET}
+ - DRONE_LETS_ENCRYPT=true
```
Note that Woodpecker uses the hostname from the `DRONE_HOST` environment variable when requesting certificates. For example, if `DRONE_HOST=https://foo.com` the certificate is requested for `foo.com`.
>Once enabled you can visit your website at both the http and the https address
## Certificate Cache
Woodpecker writes the certificates to the below directory:
```
/var/lib/drone/golang-autocert
```
## Certificate Updates
Woodpecker uses the official Go acme library which will handle certificate upgrades. There should be no addition configuration or management required.

View file

@ -0,0 +1,67 @@
# Prometheus
Woodpecker is compatible with Prometheus and exposes a `/metrics` endpoint. Please note that access to the metrics endpoint is restricted and requires an authorization token with administrative privileges.
```yaml
global:
scrape_interval: 60s
scrape_configs:
- job_name: 'drone'
bearer_token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
static_configs:
- targets: ['woodpecker.domain.com']
```
## Authorization
An administrator will need to generate a user api token and configure in the prometheus configuration file as a bearer token. Please see the following example:
```diff
global:
scrape_interval: 60s
scrape_configs:
- job_name: 'drone'
+ bearer_token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
static_configs:
- targets: ['woodpecker.domain.com']
```
## Metric Reference
List of prometheus metrics specific to Woodpecker:
```
# HELP drone_build_count Build count.
# TYPE drone_build_count counter
drone_build_count{branch="master",pipeline="total",repo="laszlocph/woodpecker",status="success"} 3
drone_build_count{branch="mkdocs",pipeline="total",repo="laszlocph/woodpecker",status="success"} 3
# HELP drone_build_time Build time.
# TYPE drone_build_time gauge
drone_build_time{branch="master",pipeline="total",repo="laszlocph/woodpecker",status="success"} 116
drone_build_time{branch="mkdocs",pipeline="total",repo="laszlocph/woodpecker",status="success"} 155
# HELP drone_build_total_count Total number of builds.
# TYPE drone_build_total_count gauge
drone_build_total_count 1025
# HELP drone_pending_jobs Total number of pending build processes.
# TYPE drone_pending_jobs gauge
drone_pending_jobs 0
# HELP drone_repo_count Total number of repos.
# TYPE drone_repo_count gauge
drone_repo_count 9
# HELP drone_running_jobs Total number of running build processes.
# TYPE drone_running_jobs gauge
drone_running_jobs 0
# HELP drone_user_count Total number of users.
# TYPE drone_user_count gauge
drone_user_count 1
# HELP drone_waiting_jobs Total number of builds waiting on deps.
# TYPE drone_waiting_jobs gauge
drone_waiting_jobs 0
# HELP drone_worker_count Total number of workers.
# TYPE drone_worker_count gauge
drone_worker_count 4
```

View file

@ -1,11 +1,5 @@
**Table of Contents**
- [Apache](#apache)
- [Nginx](#nginx)
- [Caddy](#caddy)
- [Ngrok](#ngrok)
# Apache
This guide provides a brief overview for installing Drone server behind the Apache2 webserver. This is an example configuration:
## Apache
This guide provides a brief overview for installing Woodpecker server behind the Apache2 webserver. This is an example configuration:
```nohighlight
ProxyPreserveHost On
@ -34,16 +28,16 @@ ProxyPass / http://127.0.0.1:8000/
ProxyPassReverse / http://127.0.0.1:8000/
```
# Nginx
## Nginx
This guide provides a basic overview for installing Drone server behind the nginx webserver. For more advanced configuration options please consult the official nginx [documentation](https://www.nginx.com/resources/admin-guide/).
This guide provides a basic overview for installing Woodpecker server behind the nginx webserver. For more advanced configuration options please consult the official nginx [documentation](https://www.nginx.com/resources/admin-guide/).
Example configuration:
```nginx
server {
listen 80;
server_name drone.example.com;
server_name woodpecker.example.com;
location / {
proxy_set_header X-Forwarded-For $remote_addr;
@ -65,7 +59,7 @@ You must configure the proxy to set `X-Forwarded` proxy headers:
```diff
server {
listen 80;
server_name drone.example.com;
server_name woodpecker.example.com;
location / {
+ proxy_set_header X-Forwarded-For $remote_addr;
@ -81,12 +75,12 @@ server {
}
```
# Caddy
## Caddy
This guide provides a brief overview for installing Drone server behind the [Caddy webserver](https://caddyserver.com/). This is an example caddyfile proxy configuration:
This guide provides a brief overview for installing Woodpecker server behind the [Caddy webserver](https://caddyserver.com/). This is an example caddyfile proxy configuration:
```nohighlight
drone.mycompany.com {
woodpecker.mycompany.com {
gzip {
not /stream/
}
@ -99,7 +93,7 @@ drone.mycompany.com {
You must disable gzip compression for streamed data otherwise the live updates won't be instant:
```diff
drone.mycompany.com {
woodpecker.mycompany.com {
+ gzip {
+ not /stream/
+ }
@ -113,7 +107,7 @@ drone.mycompany.com {
You must configure the proxy to enable websocket upgrades:
```diff
drone.mycompany.com {
woodpecker.mycompany.com {
gzip {
not /stream/
}
@ -127,7 +121,7 @@ drone.mycompany.com {
You must configure the proxy to include `X-Forwarded` headers using the `transparent` directive:
```diff
drone.mycompany.com {
woodpecker.mycompany.com {
gzip {
not /stream/
}
@ -138,7 +132,7 @@ drone.mycompany.com {
}
```
# Ngrok
## Ngrok
After installing [ngrok](https://ngrok.com/), open a new console and run:
```

View file

@ -1,29 +1,31 @@
Drone supports ssl configuration by mounting certificates into your container.
# SSL
Woodpecker supports ssl configuration by mounting certificates into your container.
```diff
services:
drone-server:
image: drone/drone:{{% version %}}
woodpecker-server:
image: laszlocloud/woodpecker-server:v0.9.0
ports:
+ - 80:80
+ - 443:443
- 9000:9000
volumes:
- /var/lib/drone:/var/lib/drone/
+ - /etc/certs/drone.foo.com/server.crt:/etc/certs/drone.foo.com/server.crt
+ - /etc/certs/drone.foo.com/server.key:/etc/certs/drone.foo.com/server.key
+ - /etc/certs/woodpecker.foo.com/server.crt:/etc/certs/woodpecker.foo.com/server.crt
+ - /etc/certs/woodpecker.foo.com/server.key:/etc/certs/woodpecker.foo.com/server.key
restart: always
environment:
+ - DRONE_SERVER_CERT=/etc/certs/drone.foo.com/server.crt
+ - DRONE_SERVER_KEY=/etc/certs/drone.foo.com/server.key
+ - DRONE_SERVER_CERT=/etc/certs/woodpecker.foo.com/server.crt
+ - DRONE_SERVER_KEY=/etc/certs/woodpecker.foo.com/server.key
```
Update your configuration to expose the following ports:
```diff
services:
drone-server:
image: drone/drone:{{% version %}}
woodpecker-server:
image: laszlocloud/woodpecker-server:v0.9.0
ports:
+ - 80:80
+ - 443:443
@ -34,44 +36,44 @@ Update your configuration to mount your certificate and key:
```diff
services:
drone-server:
image: drone/drone:{{% version %}}
woodpecker-server:
image: laszlocloud/woodpecker-server:v0.9.0
ports:
- 80:80
- 443:443
- 9000:9000
volumes:
- /var/lib/drone:/var/lib/drone/
+ - /etc/certs/drone.foo.com/server.crt:/etc/certs/drone.foo.com/server.crt
+ - /etc/certs/drone.foo.com/server.key:/etc/certs/drone.foo.com/server.key
+ - /etc/certs/woodpecker.foo.com/server.crt:/etc/certs/woodpecker.foo.com/server.crt
+ - /etc/certs/woodpecker.foo.com/server.key:/etc/certs/woodpecker.foo.com/server.key
```
Update your configuration to provide the paths of your certificate and key:
```diff
services:
drone-server:
image: drone/drone:{{% version %}}
woodpecker-server:
image: laszlocloud/woodpecker-server:v0.9.0
ports:
- 80:80
- 443:443
- 9000:9000
volumes:
- /var/lib/drone:/var/lib/drone/
- /etc/certs/drone.foo.com/server.crt:/etc/certs/drone.foo.com/server.crt
- /etc/certs/drone.foo.com/server.key:/etc/certs/drone.foo.com/server.key
- /etc/certs/woodpecker.foo.com/server.crt:/etc/certs/woodpecker.foo.com/server.crt
- /etc/certs/woodpecker.foo.com/server.key:/etc/certs/woodpecker.foo.com/server.key
restart: always
environment:
+ - DRONE_SERVER_CERT=/etc/certs/drone.foo.com/server.crt
+ - DRONE_SERVER_KEY=/etc/certs/drone.foo.com/server.key
+ - DRONE_SERVER_CERT=/etc/certs/woodpecker.foo.com/server.crt
+ - DRONE_SERVER_KEY=/etc/certs/woodpecker.foo.com/server.key
```
# Certificate Chain
## Certificate Chain
The most common problem encountered is providing a certificate file without the intermediate chain.
> LoadX509KeyPair reads and parses a public/private key pair from a pair of files. The files must contain PEM encoded data. The certificate file may contain intermediate certificates following the leaf certificate to form a certificate chain.
# Certificate Errors
## Certificate Errors
SSL support is provided using the [ListenAndServeTLS](https://golang.org/pkg/net/http/#ListenAndServeTLS) function from the Go standard library. If you receive certificate errors or warnings please examine your configuration more closely. Please do not create issues claiming SSL is broken.
SSL support is provided using the [ListenAndServeTLS](https://golang.org/pkg/net/http/#ListenAndServeTLS) function from the Go standard library. If you receive certificate errors or warnings please examine your configuration more closely.

View file

@ -21,7 +21,7 @@ pipeline:
- echo "Testing.."
```
## Build steps are containers
### Build steps are containers
- Define any Docker image as context
- Install the needed tools in custom Docker images, use them as context
@ -35,7 +35,7 @@ pipeline:
- aws help
```
## File changes are incremental
### File changes are incremental
- Woodpecker clones the source code in the beginning pipeline
- Changes to files are persisted through steps as the same volume is mounted to all steps

192
docs/docs/server-setup.md Normal file
View file

@ -0,0 +1,192 @@
## Installation
The below [docker-compose](https://docs.docker.com/compose/) configuration can be used to start Woodpecker with a single agent.
It relies on a number of environment variables that you must set before running `docker-compose up`. The variables are described below.
```yaml
# docker-compose.yml
version: '3'
services:
woodpecker-server:
image: laszlocloud/woodpecker-server:v0.9.0
ports:
- 80:8000
- 9000
volumes:
- woodpecker-server-data:/var/lib/drone/
restart: always
environment:
- DRONE_OPEN=true
- DRONE_HOST=${DRONE_HOST}
- DRONE_GITHUB=true
- DRONE_GITHUB_CLIENT=${DRONE_GITHUB_CLIENT}
- DRONE_GITHUB_SECRET=${DRONE_GITHUB_SECRET}
- DRONE_SECRET=${DRONE_SECRET}
woodpecker-agent:
image: laszlocloud/woodpecker-agent:v0.9.0
command: agent
restart: always
depends_on:
- woodpecker-server
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
- DRONE_SERVER=woodpecker-server:9000
- DRONE_SECRET=${DRONE_SECRET}
volumes:
woodpecker-server-data:
```
> Each agent is able to process one build by default.
>
> If you have 4 agents installed and connected to the Drone server, your system will process 4 builds in parallel.
>
> You can add more agents to increase the number of parallel builds or set the agent's `DRONE_MAX_PROCS=1` environment variable to increase the number of parallel builds for that agent.
Woodpecker needs to know its own address.
You must therefore provide the address in `<scheme>://<hostname>` format. Please omit trailing slashes.
```diff
services:
woodpecker-server:
image: laszlocloud/woodpecker-server:v0.9.0
environment:
- DRONE_OPEN=true
+ - DRONE_HOST=${DRONE_HOST}
- DRONE_GITHUB=true
- DRONE_GITHUB_CLIENT=${DRONE_GITHUB_CLIENT}
- DRONE_GITHUB_SECRET=${DRONE_GITHUB_SECRET}
- DRONE_SECRET=${DRONE_SECRET}
```
Agents require access to the host machine's Docker daemon.
```diff
services:
woodpecker-agent:
image: laszlocloud/woodpecker-agent:v0.9.0
command: agent
restart: always
depends_on: [ woodpecker-server ]
+ volumes:
+ - /var/run/docker.sock:/var/run/docker.sock
```
Agents require the server address for agent-to-server communication.
```diff
services:
woodpecker-agent:
image: laszlocloud/woodpecker-agent:v0.9.0
command: agent
restart: always
depends_on: [ woodpecker-server ]
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
+ - DRONE_SERVER=woodpecker-server:9000
- DRONE_SECRET=${DRONE_SECRET}
```
The server and agents use a shared secret to authenticate communication.
This should be a random string of your choosing and should be kept private. You can generate such string with `openssl rand -hex 32`.
```diff
services:
woodpecker-server:
image: laszlocloud/woodpecker-server:v0.9.0
environment:
- DRONE_OPEN=true
- DRONE_HOST=${DRONE_HOST}
- DRONE_GITHUB=true
- DRONE_GITHUB_CLIENT=${DRONE_GITHUB_CLIENT}
- DRONE_GITHUB_SECRET=${DRONE_GITHUB_SECRET}
+ - DRONE_SECRET=${DRONE_SECRET}
woodpecker-agent:
image: laszlocloud/woodpecker-agent:v0.9.0
environment:
- DRONE_SERVER=woodpecker-server:9000
- DRONE_DEBUG=true
+ - DRONE_SECRET=${DRONE_SECRET}
```
Registration is closed by default.
This example enables open registration for users that are members of approved GitHub organizations.
```diff
services:
woodpecker-server:
image: laszlocloud/woodpecker-server:v0.9.0
environment:
+ - DRONE_OPEN=true
+ - DRONE_ORGS=dolores,dogpatch
- DRONE_HOST=${DRONE_HOST}
- DRONE_GITHUB=true
- DRONE_GITHUB_CLIENT=${DRONE_GITHUB_CLIENT}
- DRONE_GITHUB_SECRET=${DRONE_GITHUB_SECRET}
- DRONE_SECRET=${DRONE_SECRET}
```
Administrators should also be enumerated in your configuration.
```diff
services:
woodpecker-server:
image: laszlocloud/woodpecker-server:v0.9.0
environment:
- DRONE_OPEN=true
- DRONE_ORGS=dolores,dogpatch
+ - DRONE_ADMIN=johnsmith,janedoe
- DRONE_HOST=${DRONE_HOST}
- DRONE_GITHUB=true
- DRONE_GITHUB_CLIENT=${DRONE_GITHUB_CLIENT}
- DRONE_GITHUB_SECRET=${DRONE_GITHUB_SECRET}
- DRONE_SECRET=${DRONE_SECRET}
```
## Authentication
Authentication is done using OAuth and is delegated to one of multiple version control providers, configured using environment variables. The example above demonstrates basic GitHub integration.
See the complete reference for [Github](/administration/github), [Bitbucket Cloud](/administration/bitbucket), [Bitbucket Server](/administration/bitbucket_server) and [Gitlab](/administration/gitlab).
## Database
Woodpecker mounts a [data volume](https://docs.docker.com/storage/volumes/#create-and-manage-volumes) to persist the sqlite database.
See the [database settings](/administration/database) page to configure Postgresql or MySQL as database.
```diff
services:
woodpecker-server:
image: laszlocloud/woodpecker-server:v0.9.0
ports:
- 80:8000
- 9000
+ volumes:
+ - woodpecker-server-data:/var/lib/drone/
restart: always
```
## SSL
Woodpecker supports ssl configuration by mounting certificates into your container. See the [SSL guide](/administration/ssl).
Automated [Lets Encrypt](/administration/lets-encrypt) is also supported.
## Metrics
A [Prometheus endpoint](/administration/prometheus) is exposed.
## Behind a proxy
See the [proxy guide](/administration/proxy) if you want to see a setup behind Apache, Nginx, Caddy or ngrok.

View file

@ -1,9 +1,26 @@
site_name: Woodpecker
repo_name: 'laszlocph/woodpecker'
repo_url: 'https://github.com/laszlocph/woodpecker'
copyright: 'Copyright &copy; 2019 Laszlo Fogas'
nav:
- Home: index.md
- Server setup: server-setup.md
theme:
name: 'material'
logo: 'images/logo.svg'
logo: 'images/favicon.svg'
favicon: 'images/favicon.svg'
palette:
primary: 'green'
accent: 'red'
markdown_extensions:
- admonition
- codehilite:
linenums: true
linenums: true
- pymdownx.inlinehilite
extra:
social:
- type: globe
link: http://woodpecker.laszlo.cloud
- type: twitter
link: https://twitter.com/laszlocph

View file

@ -1,77 +1,20 @@
apache-libcloud==2.3.0
asn1crypto==0.24.0
awscli==1.16.89
backports-abc==0.5
backports.functools-lru-cache==1.5
backports.ssl-match-hostname==3.5.0.1
beautifulsoup4==4.8.0
boto==2.49.0
botocore==1.12.79
cachetools==2.0.1
certifi==2018.4.16
chardet==3.0.4
Click==7.0
colorama==0.3.9
crcmod==1.7
cryptography==2.6.1
docker-py==1.10.6
docker-pycreds==0.2.2
docutils==0.14
enum34==1.1.6
fluendo-eula==0.6
futures==3.2.0
google-api-core==1.2.1
google-api-python-client==1.6.7
google-auth==1.4.1
google-auth-httplib2==0.0.3
google-cloud-monitoring==0.29.0
google-compute-engine==20190801.0
googleapis-common-protos==1.5.3
grpcio==1.12.1
gWakeOnLan==0.5.1
html5lib==1.0.1
futures==3.3.0
htmlmin==0.1.12
idna==2.6
ipaddress==1.0.17
Jinja2==2.10.3
jsmin==2.2.2
livereload==2.6.1
lxml==4.4.1
Markdown==3.1.1
MarkupSafe==1.1.1
mkdocs==1.0.4
mkdocs-markdownextradata-plugin==0.1.1
mkdocs-material==4.4.3
mkdocs-minify-plugin==0.2.1
numpy==1.16.2
oauth2client==4.1.2
pep562==1.0
protobuf==3.6.0
pyasn1==0.4.2
pyasn1-modules==0.2.1
pycairo==1.16.2
pydot==1.4.1
pydot-ng==1.0.0
Pygments==2.4.2
pymdown-extensions==6.1
pyOpenSSL==19.0.0
pyparsing==2.2.0
python-apt==1.9.0+ubuntu1
python-dateutil==2.7.5
python-distutils-extra==2.39
pytz==2018.4
PyYAML==5.1.2
requests==2.18.4
rsa==3.4.2
s3transfer==0.1.13
scour==0.37
singledispatch==3.4.0.3
six==1.12.0
soupsieve==1.9.2
six==1.13.0
tornado==5.1.1
unity-lens-photos==1.0
uritemplate==3.0.0
urllib3==1.22
vboxapi==1.0
virtualenv==15.2.0
webencodings==0.5.1
websocket-client==0.47.0

View file

@ -80,7 +80,7 @@ type website struct {
func (w *website) Register(mux *httptreemux.ContextMux) {
h := http.FileServer(w.fs)
h = setupCache(h)
mux.Handler("GET", "/favicon.png", h)
mux.Handler("GET", "/favicon.svg", h)
mux.Handler("GET", "/static/*filepath", h)
mux.NotFoundHandler = w.handleIndex
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22"><path d="M1.263 2.744C2.41 3.832 2.845 4.932 4.118 5.08l.036.007c-.588.606-1.09 1.402-1.443 2.423-.38 1.096-.488 2.285-.614 3.659-.19 2.046-.401 4.364-1.556 7.269-2.486 6.258-1.12 11.63.332 17.317.664 2.604 1.348 5.297 1.642 8.107a.857.857 0 00.633.744.86.86 0 00.922-.323c.227-.313.524-.797.86-1.424.84 3.323 1.355 6.13 1.783 8.697a.866.866 0 001.517.41c2.88-3.463 3.763-8.636 2.184-12.674.459-2.433 1.402-4.45 2.398-6.583.536-1.15 1.08-2.318 1.55-3.566.228-.084.569-.314.79-.441l1.707-.981-.256 1.052a.864.864 0 001.678.408l.68-2.858 1.285-2.95a.863.863 0 10-1.581-.687l-1.152 2.669-2.383 1.372a18.97 18.97 0 00.508-2.981c.432-4.86-.718-9.074-3.066-11.266-.163-.157-.208-.281-.247-.26.095-.12.249-.26.358-.374 2.283-1.693 6.047-.147 8.319.75.589.232.876-.337.316-.67-1.95-1.153-5.948-4.196-8.188-6.193-.313-.275-.527-.607-.89-.913C9.825.555 4.072 3.057 1.355 2.569c-.102-.018-.166.103-.092.175m10.98 5.899c-.06 1.242-.603 1.8-1 2.208-.217.224-.426.436-.524.738-.236.714.008 1.51.66 2.143 1.974 1.84 2.925 5.527 2.538 9.86-.291 3.288-1.448 5.763-2.671 8.385-1.031 2.207-2.096 4.489-2.577 7.259a.853.853 0 00.056.48c1.02 2.434 1.135 6.197-.672 9.46a96.586 96.586 0 00-1.97-8.711c1.964-4.488 4.203-11.75 2.919-17.668-.325-1.497-1.304-3.276-2.387-4.207-.208-.18-.402-.237-.495-.167-.084.06-.151.238-.062.444.55 1.266.879 2.599 1.226 4.276 1.125 5.443-.956 12.49-2.835 16.782l-.116.259-.457.982c-.356-2.014-.85-3.95-1.33-5.84-1.38-5.406-2.68-10.515-.401-16.254 1.247-3.137 1.483-5.692 1.672-7.746.116-1.263.216-2.355.526-3.252.905-2.605 3.062-3.178 4.744-2.852 1.632.316 3.24 1.593 3.156 3.42zm-2.868.62a1.177 1.177 0 10.736-2.236 1.178 1.178 0 10-.736 2.237z"/></svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View file

@ -87,7 +87,7 @@ module.exports = {
filename: "static/vendor.[hash].js"
}),
new HtmlWebpackPlugin({
favicon: "src/public/favicon.png",
favicon: "src/public/favicon.svg",
template: "src/index.html"
})
].concat(