diff --git a/README.md b/README.md index cf09e0f..6e79ed5 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,21 @@ docker-devbox ============= +![Docker Devbox logo](docs/logo/Logo-text.svg) + Docker Devbox is a set of tools build on top of Docker that automates environments setup for web applications, from development to production. +You can see it as a linux machine (a box) that contains several tools for web developers, the biggest one being docker. It relies on [ddb](https://inetum-orleans.github.io/docker-devbox-ddb/), a command line tool that provides features to generate, activate and adjust configuration files based on a single overridable and extendable configuration, while enhancing the developer experience and reducing manual operations. +This project has no relationship with [Microsoft Dev Box](https://azure.microsoft.com/en-us/products/dev-box) +that has been created after this project. + +Docker Devbox does not need Docker Desktop, and, as we understand it, is usable in a commercial company at no cost. + # Design goals * Give the developer a clear and native experience, but use docker containers under the hood. @@ -34,34 +42,44 @@ configuration, while enhancing the developer experience and reducing manual oper and [fixuid](https://github.com/boxboat/fixuid) integration. * Configure each target environment (`dev`, `stage`, `prod`) with environment variables only. * Introduce environment variables into configuration files with a template - engine ([Mo - Mustache Templates in Bash](https://github.com/tests-always-included/mo)). + engine ([Jinja](https://jinja.palletsprojects.com/en/stable/), [Jsonnet](https://jsonnet.org/) and [ytt](https://carvel.dev/ytt/)) and automatically add them to the .gitignore file. * Enable configuration files matching the active environment with simple symlinks creation - automation ([mo pure bash templating engine](https://github.com/tests-always-included/mo)). + automation. * Switch to a real public domain name with no pain ([Traefik](https://traefik.io/) and [Let's Encrypt](https://letsencrypt.org/)). -* Access application from a private network remotely through an automated SSH tunnel ([ngrok](https://ngrok.com/) - , [Serveo](https://serveo.net/) or [ssi.sh](https://github.com/antoniomika/sish)) +* DJP (ddb jsonnet packages): docker + configuration + tools to quickly bootstrap a project ([Cookiecutter](https://github.com/cookiecutter/cookiecutter)) +* ... -# Requirements +# Setup +## Requirements -Docker Devbox runs natively on any Linux only, but Windows and MacOS users may use -[docker-devbox-vagrant](https://github.com/inetum-orleans/docker-devbox-vagrant) to run it inside a Vagrant managed -VirtualBox VM based on Ubuntu Server. +As the name implies, Docker Devbox requires the docker engine for linux. +This mean that Windows and MacOS users will need to host a linux in some way. +There is no need to use Docker Desktop for that. -* Docker >= 18.09.6 -* Docker compose plugin >= 2 +To ease the installation of such environment on windows, you may use: +- WSL2 with [docker-devbox-wsl](https://github.com/inetum-orleans/docker-devbox-wsl) +- Vagrant + Virtualbox with [docker-devbox-vagrant](https://github.com/inetum-orleans/docker-devbox-vagrant) + +If you decide to go the manual route, you will need: +* Docker with docker compose plugin v2 * GNU Bash >= 4.0 * curl -# Install or Update +## Devbox installation environment -``` +```sh curl -L https://github.com/inetum-orleans/docker-devbox/raw/master/installer | bash ``` -This will install everything required for Docker Devbox, but docker, docker compose and bash should be installed -manually -before. +You may customize the installation by passing environment variables to the bash command, see the example at the bottom of the [Installation environment variables](#installation-environment-variables) section. + +This will install everything required for Docker Devbox, but docker, +docker compose and bash should be installed manually before. + +It will also install: +* [Traefik](https://traefik.io/) : A container used to route the network traffic on port 80/443 to the right application. (See the [Configuration with a DNS](#configuration-with-a-dns) section) +* [CFSSL](https://github.com/cloudflare/cfssl) : A container to generate HTTPS certificates for the apps in your docker containers. Docker Devbox will install [Traefik](https://traefik.io/) in a docker container and binds `tcp/80`,`tcp/443` to host, so those ports should be available. @@ -70,119 +88,9 @@ Port `tcp/7780` should also be available for CFSSL container (local certificate *Installation script may ask for sudo password to install some dependencies, like curl, git and make.* -## Development domain name configuration (`.test`) - -To access application through `.test` development domain name, you have to setup your system for those domains to be -resolved as docker host IP. - -On Linux, dnsmasq can be used for this purpose. - -On Windows, Acrylic DNS proxy can be used for this purpose. - -#### Linux (dnsmasq) - -- Ubuntu Server (without NetworkManager) - -``` -sudo apt-get install -y dnsmasq - -DOCKER_HOST_IP=$(ip -4 addr show docker0 | grep -Po 'inet \K[\d.]+') -sudo sh -c "echo address=/.test/$DOCKER_HOST_IP>/etc/dnsmasq.d/test-domain-to-docker-host-ip" - -sudo service dnsmasq restart -``` - -- Ubuntu Desktop (with NetworkManager) - -NetworkManager from desktop brings it's own dnsmasq daemon. - -``` -sudo mv /etc/resolv.conf /etc/resolve.conf.bak -sudo ln -s /var/run/NetworkManager/resolv.conf /etc/resolv.conf - -sudo sh -c 'cat << EOF > /etc/NetworkManager/conf.d/use-dnsmasq.conf -[main] -dns=dnsmasq -EOF' - -sudo sh -c 'cat << EOF > /etc/NetworkManager/dnsmasq.d/test-domain-to-docker-host-ip -address=/.test/$(ip -4 addr show docker0 | grep -Po "inet \K[\d.]+") -EOF' - -sudo service NetworkManager restart -``` - -#### Windows (Acrylic DNS proxy) - -Download [Acrylic DNS proxy](https://mayakron.altervista.org) for Windows, and perform installation. - -Then open Acrylic UI and configure the Host configuration with such entry - -``` -192.168.1.100 *.test -``` - -The IP address should match the IP of the docker engine. - -## Configure local CA certificate - -Docker Devbox automatically generates development certificate for HTTPS support, but you need to register the local -CA certificate using mkcert. - -#### Linux - -Run the following commands from docker devbox shell. - -``` -# This dependency is required to support Chrome and Firefox. -sudo apt-get install libnss3-tools +Open a browser and check that you can navigate to `http:///` you should see the traefik's "404 page not found". -# Uninstall any previous CA cert -mkcert -uninstall - -# Move to cfssl container directory -cd ~/.docker-devbox/cfssl - -# Replace default mkcert key/pair with CFSSL public key. -rm -Rf $(mkcert -CAROOT) && mkdir -p $(mkcert -CAROOT) -docker compose cp intermediate:/etc/cfssl/ca.pem $(mkcert -CAROOT)/rootCA.pem - -# Install CFSSL CA Certificate with mkcert. -mkcert -install -``` - -#### Windows - -On Windows, you should install the CA certificate inside the VM where docker-devbox is installed with the previous -linux procedure, but you should also install the CA certificate on your host, for browser to aknowlegdge the -development certificates. - -- Download [mkcert for Windows](https://github.com/FiloSottile/mkcert/releases), and set `CAROOT` environment variable - to some directory, like `C:\mkcert-ca`. - -- Extract the CFSSL ca certificate from docker with the following command - -``` -# Inside docker-devbox shell -cd ~/.docker-devbox/cfssl -docker compose cp intermediate:/etc/cfssl/ca.pem ../certs/mkcert-ca/rootCA.pem -``` - -- Copy `~/.docker-devbox/certs/mkcert-ca/rootCA.pem` to the host, inside `CAROOT` - directory. - -- Close all `cmd.exe`, and open a new one to check that `CAROOT` environment variable is defined. - -``` -# This should output CAROOT environment variable -mkcert -CAROOT -``` - -- Install CA certificate - -``` -mkcert -install -``` +// TODO: write a ddb project that can check if we can navigate to an app on port 1212 ## Installation environment variables @@ -224,3 +132,45 @@ curl -L https://github.com/inetum-orleans/docker-devbox/raw/master/installer | \ DOCKER_DEVBOX_CI=1 \ bash ``` + +# Optional setup +## Configuration with a DNS + +Using an IP address like `http://192.168.99.100:1212/` is not very convenient because: +* We need to remember the IP address and the port of our application +* If we need to run multiple applications at the same time, we need to open several ports +* If several devs have different configurations, the IP/Port might not be the same across the team. + +It would be better to use a name like `http://myapp.test` and `http://mysecondapp.test`, and be able to call both of them at once. +Even better, sometimes we need apis, and we can call them at `http://api.myapp.test` and share cookies with it because it is a subdomain. You're likely to have that kind of domain hierarchy in prod anyway, and being able to figure out things like CORS locally is really valuable. + +Lastly, if you want to let traefik handle the complexity of https certificates ([see next section](#generate-certificates-for-your-applications)) for you and your application, it needs a way to route your request to your app, and the domain name is the easiest way. + +[Read on to know how to configure the DNS for your apps](docs/dns.md) + +## Generate HTTPS certificates for your applications + +More and more websites are using https (if not most), but the same cannot be said of development environments or even QA environments, which are often HTTP because generating valid HTTPS certificates on internal network can be a headache. + +However, [more and more features are requiring a Secure Context](https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts/features_restricted_to_secure_contexts). + +What if it could be done as easily as: + +```bash +ddb configure +dc up -d +``` +? + +[You just need to install the certificates on your machine :wink:](docs/certs.md) + +# Story +The project began at Orléans, France, at Inetum (formerly known as GFI) around 2019 as a way to improve and standardize the developers workflow in the company. + +The project has changed and improved since then, but it's used daily by the developers at Inetum Orléans. + +# Acknowledgments + +- [@toilal](https://github.com/toilal) for the original idea and dev +- Axel Boulet for the logo design +- All the devs at Inetum Orléans that are using the Docker Devbox daily and are providing feedback to improve it. \ No newline at end of file diff --git a/certs/.gitignore b/certs/.gitignore deleted file mode 100644 index c96a04f..0000000 --- a/certs/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore \ No newline at end of file diff --git a/docs/certs.md b/docs/certs.md new file mode 100644 index 0000000..d108b57 --- /dev/null +++ b/docs/certs.md @@ -0,0 +1,60 @@ + +## Configure local CA certificate + +Docker Devbox automatically generates development certificate for HTTPS support, but you need to register the local +CA certificate using mkcert. + +#### Linux + +Run the following commands from docker devbox shell. + +``` +# This dependency is required to support Chrome and Firefox. +sudo apt-get install libnss3-tools + +# Uninstall any previous CA cert +mkcert -uninstall + +# Move to cfssl container directory +cd ~/.docker-devbox/cfssl + +# Replace default mkcert key/pair with CFSSL public key. +rm -Rf $(mkcert -CAROOT) && mkdir -p $(mkcert -CAROOT) +docker compose cp intermediate:/etc/cfssl/ca.pem $(mkcert -CAROOT)/rootCA.pem + +# Install CFSSL CA Certificate with mkcert. +mkcert -install +``` + +#### Windows + +On Windows, you should install the CA certificate inside the VM where docker-devbox is installed with the previous +linux procedure, but you should also install the CA certificate on your host, for browser to aknowlegdge the +development certificates. + +- Download [mkcert for Windows](https://github.com/FiloSottile/mkcert/releases), and set `CAROOT` environment variable + to some directory, like `C:\mkcert-ca`. + +- Extract the CFSSL ca certificate from docker with the following command + +``` +# Inside docker-devbox shell +cd ~/.docker-devbox/cfssl +docker compose cp intermediate:/etc/cfssl/ca.pem ../certs/mkcert-ca/rootCA.pem +``` + +- Copy `~/.docker-devbox/certs/mkcert-ca/rootCA.pem` to the host, inside `CAROOT` + directory. + +- Close all `cmd.exe`, and open a new one to check that `CAROOT` environment variable is defined. + +``` +# This should output CAROOT environment variable +mkcert -CAROOT +``` + +- Install CA certificate + +``` +mkcert -install +``` \ No newline at end of file diff --git a/docs/dns.md b/docs/dns.md new file mode 100644 index 0000000..a76db50 --- /dev/null +++ b/docs/dns.md @@ -0,0 +1,327 @@ +# Configuration with a DNS + +This documentation describes how to configure your applications to be accessible through a domain name like `myapp.test` instead of an IP address (like `192.168.99.100`). + +```mermaid +--- +title: Traefik maps the domain names to the corresponding container +--- + graph LR; + myapp.test-->Traefik; + api.my-second-app.test-->Traefik; + Traefik-->myapp[myapp frontend]; + Traefik-->mysecondapp-api[MySecondApp API]; +``` + +Make sure to understand how it works before moving to the configuration section. + +NOTE: In this document, the Docker devbox is considered to have the IP address `192.168.99.100`. If you are running on windows, the IP address of windows doesn't matter for the DNS configuration, it's only the WSL/Virtual box IP that matters. +However, in WSL mirrored mode, the boundaries are blurred and any IP address of the windows machine should work. +It's however easier to pick a fixed IP address that we control. + +## How it works + +When you type "http://myapp.test" in your browser, it will make a query to a DNS server, that will reply with the IP address of the server. The browser will next ask the server at that IP for the page "http://myapp.test". + +In our case, that server is Traefik and should be configured so that any request for "myapp.test" should go to the "myapp frontend" container. Traefik then relays the request to your container, and your app can reply. + +This can be summarized in the following diagram: + +```mermaid +--- +title: Steps needed to reach your app container +--- + graph TD; + DNSConfig["1 - Where is the DNS Server for myapp.test ?"]-->DNSResolve; + DNSResolve["2 - DNS Resolution : myapp.test gives 192.168.99.100"]-->IP2Traefik; + IP2Traefik["3 - Reach traefik on 192.168.99.100 port 80/443"]-->TraefikRouting; + TraefikRouting["4 - Which container can handle myapp.test ? That's myapp-frontend on port 5173"]-->Proxy; + Proxy["5 - Traefik reaches myapp-frontend on port 5173 and passes the request"] +``` + +The whole chain needs to work for your application to reply anything. In the following sections, I will detail the steps (beginning with step 5 down to step 1). + +I'm trying to make this page as easily understandable as possible. If you don't understand anything, please file an issue :slightly_smiling_face: + +Usually, everything works out of the box, except from [Step 2](#step-2--you-can-resolve-the-domain-name) and [Step 1](#step-1--your-browseros-uses-the-dns-server-properly), which need an extra configuration. + +## Step 5 : Your app is up and running in your container + +To contact your app, your app must be running in your container. Make sure that's the case and that it listens on all network traffic, not only localhost. For example, make sure to use the [`server.host` (vite --host) option in vite.](https://vite.dev/config/server-options.html#server-host) + +### Usual causes of failure + +- Your app isn't started +- Your app isn't listening on the port you're expecting +- Your app doesn't allow http traffic from anything other than localhost +- You ran your command outside your container (for example: you ran `npm run dev`, but it's not using the `npm` binary from your container) + +### How to troubleshoot + +If you have curl installed in your container (`node` is the name of my service in the docker-compose.yml), you can try: + +```sh +docker compose exec node curl http://localhost:5173 +``` +If it doesn't return some HTML, your application is not running. If it is running, you might try this command to know if the application is accessible through the network: + +```sh +docker compose exec node bash -c "curl http://\$(hostname):51 +73" +``` + +NOTE for vite: This message : +``` +Blocked request. This host ("0e5849fa84b2") is not allowed. +To allow this host, add "0e5849fa84b2" to `server.allowedHosts` in vite.config.js. +``` +means it works for our use case. If you still have this kind of message (with the domain name), you will need to configure server.allowedHosts. + +## Step 4 : Your app is registered within Traefik + +With Docker Devbox, we made the decision to use dynamic routing through docker container labels and [traefik's Host matcher](https://doc.traefik.io/traefik/routing/routers/#host-and-hostregexp). + +In a docker-compose.yaml file, it may look like this: + +```yaml + traefik.enable: 'true' + traefik.http.routers.ddb-symfony-vue-demo-tls.rule: Host(`ddb-symfony-vue-demo.test`) + traefik.http.routers.ddb-symfony-vue-demo-tls.service: ddb-symfony-vue-demo + traefik.http.routers.ddb-symfony-vue-demo-tls.tls: 'true' + traefik.http.routers.ddb-symfony-vue-demo.rule: Host(`ddb-symfony-vue-demo.test`) + traefik.http.routers.ddb-symfony-vue-demo.service: ddb-symfony-vue-demo + traefik.http.services.ddb-symfony-vue-demo.loadbalancer.server.port: '5173' +``` + +ddb provides a [`ddb.VirtualHost`](https://inetum-orleans.github.io/docker-devbox-ddb/features/jsonnet/#ddbvirtualhost) to help you write such labels. + +``` +ddb.VirtualHost('5173', 'ddb-symfony-vue-demo.test') +``` + +you may also derive the domain name automatically by using the `core.domain.value` ddb variable. + +``` +local domain = std.extVar('core.domain.value'); +``` + +More info on core.domain values [here](https://inetum-orleans.github.io/docker-devbox-ddb/features/core/) + +### Usual causes of failure + +- The docker-compose.yml file is not properly configured +- The server port is not configured to the same port than the one your app is listening on +- You made a change to your docker-compose.yml but you forget to re create your containers by running `docker compose down && docker compose up -d` + +### How to troubleshoot + +Show labels on your containers: ([source](https://gist.github.com/steve-jansen/a90f942e05e326e817aaeb04dff3f4e6?permalink_comment_id=4340723#gistcomment-4340723)) +```bash +docker inspect -f '{{ range $k, $v := .Config.Labels -}} +{{ $k }}={{ $v }}; +{{ end -}}' ddb-symfony-vue-demo-node-1 +``` + +The traefik container may also have some logs indicating what's wrong: +``` +docker logs traefik +``` + +## Step 3 : You can reach traefik on the IP and port + +This might be the easiest one : Traefik needs to be up and listening. + +### Usual causes of failure + +- Traefik container is not up (go to `~/.docker-devbox/traefik` and `docker compose up -d`) +- You're not contacting the correct IP address +- A firewall is blocking the request + +### How to troubleshoot + +Open a browser and contact `http://192.168.99.100` (if that's your devbox's IP address). You should see a "404 page not found" message. + +If you are on linux and the devbox is installed locally, `http://localhost` should show the traefik dashboard. + +If your devbox is on another machine (WSL, virtual machine), run `curl http://localhost/` on that machine to see if traefik is running. + +## Step 2 : You can resolve the domain name + +Some DNS server need to resolve your request. + +Here are a few options: +
+Already own a DNS server, or your company does and is willing to put additional records for that. + +Great, you're probably already using it and don't need to worry about [Step 1](#step-1--your-browseros-uses-the-dns-server-properly) ! +
+
+You run your coredns server locally. + +CoreDNS can be installed without any administrative privileges, but you might need some to complete the [Step 1](#step-1--your-browseros-uses-the-dns-server-properly). + +Here is an example Corefile + +```Corefile +.:53 { + # Resolve *.test to 192.168.99.100 + template IN A test { + match (^|[.])(?P.*)[.]test[.]$ + answer "{{ .Name }} 60 IN A 192.168.99.100" + } + + errors +} +``` +
+
+You are on windows and want something that starts with your OS, try Acrylic DNS. + +Download [Acrylic DNS](https://mayakron.altervista.org/support/acrylic/Home.htm) (the setup). Install it, and edit the hosts file to add this line (adapted with your IP address): + +``` +192.168.99.100 *.test +``` + +
+
+You are on linux, you can try dnsmasq + +NOTE: this procedure has been ported from a previous version of the documentation and has not been tested since. + +- Ubuntu Server (without NetworkManager) + +``` +sudo apt-get install -y dnsmasq + +DOCKER_HOST_IP=$(ip -4 addr show docker0 | grep -Po 'inet \K[\d.]+') +sudo sh -c "echo address=/.test/$DOCKER_HOST_IP>/etc/dnsmasq.d/test-domain-to-docker-host-ip" + +sudo service dnsmasq restart +``` + +- Ubuntu Desktop (with NetworkManager) + +NetworkManager from desktop brings it's own dnsmasq daemon. + +``` +sudo mv /etc/resolv.conf /etc/resolve.conf.bak +sudo ln -s /var/run/NetworkManager/resolv.conf /etc/resolv.conf + +sudo sh -c 'cat << EOF > /etc/NetworkManager/conf.d/use-dnsmasq.conf +[main] +dns=dnsmasq +EOF' + +sudo sh -c 'cat << EOF > /etc/NetworkManager/dnsmasq.d/test-domain-to-docker-host-ip +address=/.test/$(ip -4 addr show docker0 | grep -Po "inet \K[\d.]+") +EOF' + +sudo service NetworkManager restart +``` + +
+
+You cannot/don't want to install anything on your machine, but you can edit your hosts file + +Just add an entry to your hosts file (`/etc/hosts` on linux, `C:\Windows\System32\drivers\etc\hosts` on windows) each time you add a new domain name (no wildcard support like `*.test`). This requires administrative privileges on your OS to do so. + +``` +192.168.99.100 myapp.test +192.168.99.100 api.my-second-app.test +``` +
+
+ +You cannot touch your machine's configuration, but still want the benefits of a DNS-like name (cookie sharing, https through traefik...) + +You can use a service like `traefik.me`. + +For example, if your traefik is at `192.168.99.100`, you can reach your application through `http://myapp.192-168-99-100.traefik.me`. + +The only change you need is to configure `core.domain.ext`. + +Inside your devbox, create or edit your `~/ddb.local.yaml` with: + +```yaml +core: + domain: + ext: 192-168-99-100.traefik.me +``` + +go back to your project and run `ddb configure` again. Go back to [step 4](#step-4--your-app-is-registered-within-traefik) to make sure the whole chain still works. Don't forget to restart your app container. + +
+
+You give up and bind ports on your machine + +You don't need traefik at all and call your app on something like `http://ip:port`. You need to manage port collision between your app yourself. + + +### Usual causes of failure + +- The DNS server used doesn't know the IP address +- The DNS server is not running + +### How to troubleshoot + +On windows, run this command (127.0.0.1 assumes the DNS is installed locally. Use the DNS server IP instead if not.): + +``` +nslookup myapp.test 127.0.0.1 +``` + +It should resolve to the IP you set. + +On linux, you may use `dig @127.0.0.1 myapp.test +short` + +## Step 1 : Your OS uses the DNS server properly + +If you used a service like traefik.me or a DNS server that is already configured, you have nothing to do. +Otherwise you need to tell your OS to use your new DNS server. +On linux, it depends on how `/etc/resolv.conf` is managed. +On windows, you need to set the DNS adress as a primary DNS server on one of your *active* network card. + +You likely can't pick any card though. +Some network cards are managed by VPN applications, and the DNS address that you may be able to change there will be overwritten the next time you connect. +Some wifi hotspots require that you use the DNS provided by the DHCP to display their captive portal. It's not a good idea to override it there. + +If you have installed your devbox with Vagrant, you have a dedicated "Virtualbox Host Only" network card with the IP 192.168.99.1 (by default). You can change the DNS address there because that parameter is not used otherwise. + +
+ +If you don't have any network card that you can use, you can create a new network card : + + +- Open the Device Management window as administrator. You may open an admin command prompt and type `devmgmt.msc` +- Under "Action", click "Add legacy hardware", "Next" +- "Install the Hardware that I manually select from a list (Advanced)", "Next" +- Choose "Network adapters", "Next" +- From the left list, pick "Microsoft", and on the right "Microsoft KM-TEST Loopback adapter" + +Open the network adapter settings and set it a fixed IP address, like 172.0.0.1 (it's not a typo for 127.0.0.1) +
+ +On the properties of the network adapter, set the primary DNS address to the address of your DNS server. If you installed acrylic or coredns locally, you can type `127.0.0.1`. + +### Usual causes of failure + +- Traefik container is not up (go to `~/.docker-devbox/traefik` and `docker compose up -d`) +- You're not contacting the correct IP address +- A firewall is blocking the request + +### How to troubleshoot + +Clear dns cache: + +``` +ipconfig /flushdns +``` + +Try to ping the dns name: + +``` +ping myapp.test +``` + +If the ping command says "Could not find host ...", the configuration doesn't work. Otherwise, the domain name is resolved to the IP address that is shown in the output. \ No newline at end of file diff --git a/docs/logo/Logo-side-text.svg b/docs/logo/Logo-side-text.svg new file mode 100644 index 0000000..9066946 --- /dev/null +++ b/docs/logo/Logo-side-text.svg @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/logo/Logo-text.svg b/docs/logo/Logo-text.svg new file mode 100644 index 0000000..d5c3d1e --- /dev/null +++ b/docs/logo/Logo-text.svg @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/logo/Logo-variant.svg b/docs/logo/Logo-variant.svg new file mode 100644 index 0000000..fe6f209 --- /dev/null +++ b/docs/logo/Logo-variant.svg @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/logo/Logo.svg b/docs/logo/Logo.svg new file mode 100644 index 0000000..265c9b6 --- /dev/null +++ b/docs/logo/Logo.svg @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +