standard-procedure-anvil 0.1.4 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +73 -99
- data/assets/cloudinit/docker.yml +50 -0
- data/assets/cloudinit/{dokku.ubuntu-22.yml → dokku.yml} +20 -12
- data/assets/cloudinit/{memcached.ubuntu-22.yml → memcached.yml} +2 -1
- data/assets/cloudinit/{mysql.ubuntu-22.yml → mysql.yml} +2 -1
- data/assets/cloudinit/{opensearch.ubuntu-22.yml → opensearch.yml} +15 -6
- data/assets/cloudinit/{redis.ubuntu-22.yml → redis.yml} +2 -1
- data/checksums/standard-procedure-anvil-0.1.5.gem.sha512 +1 -0
- data/checksums/standard-procedure-anvil-0.1.6.gem.sha512 +1 -0
- data/checksums/standard-procedure-anvil-0.1.7.gem.sha512 +1 -0
- data/checksums/standard-procedure-anvil-0.2.0.gem.sha512 +1 -0
- data/lib/anvil/app/deploy.rb +16 -0
- data/lib/anvil/app/host_deployer.rb +88 -0
- data/lib/anvil/app/host_installer.rb +24 -10
- data/lib/anvil/app/host_scaler.rb +31 -0
- data/lib/anvil/app/scale.rb +15 -0
- data/lib/anvil/app.rb +31 -0
- data/lib/anvil/version.rb +1 -1
- metadata +16 -8
- data/assets/cloudinit/dokku.mysql.opensearch.ubuntu-22.yml +0 -126
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bd79d747f6dacee61d78024e0bea3789ce4e143fb8307c5f21df6dfdac5ca357
|
4
|
+
data.tar.gz: d633f9eff054f41ab3e0253606f920d7e258235f25fc84b2eadf6f336125e773
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 903ec97ce720953550c05f15cb15aa5d420f5e510645f688991a860c213ec2025da72049bfae1198d569390bd9cdf1b6c38bfb4e62ff05f470659ee3d5282a2d
|
7
|
+
data.tar.gz: ef6be87643818b9c07183d6cbc5fa4e4a6cea75b00a692313ff088cf0754a00aad33a94ba7b459daf644cb7a94d64c38f1d57bdef48434ec3d5c471d5c06043f
|
data/README.md
CHANGED
@@ -12,123 +12,97 @@ gem install standard-procedure-anvil
|
|
12
12
|
|
13
13
|
### To build a new server
|
14
14
|
|
15
|
-
|
15
|
+
Ultimately the plan is to use [Fog](https://github.com/fog/fog) to handle building servers.
|
16
16
|
|
17
|
-
|
17
|
+
But until then, you can prepare your servers using [CloudInit](https://cloudinit.readthedocs.io/en/latest/)
|
18
18
|
|
19
|
-
|
19
|
+
A cloudinit file is a YML file that you load into a virtual machine while it is being created. As the server boots, uses the cloudinit configuration to install software and set itself up. With most cloud hosting providers, you will find an option for "user data", or something similar, on the "create a new server" page.
|
20
20
|
|
21
|
-
|
21
|
+
So firstly we ask Anvil which cloudinit configurations it has available:
|
22
22
|
|
23
|
-
|
23
|
+
```sh
|
24
|
+
anvil cloudinit list
|
25
|
+
```
|
26
|
+
|
27
|
+
This will give us a list of prewritten cloud init scripts - of which dokku is probably the one we're most interested in.
|
28
|
+
|
29
|
+
Next we tell anvil to generate our configuration:
|
30
|
+
|
31
|
+
```sh
|
32
|
+
anvil cloudinit generate dokku --user app --public-key ~/.ssh/my_key.pub > ~/Desktop/my_server.yml
|
33
|
+
```
|
34
|
+
|
35
|
+
Anvil generates a dokku configuration (and places it on our desktop) that will create an Ubuntu 22.04 box with docker and dokku preinstalled. Plus it will create a user called `app` that can log in through SSH using a public key `my_key.pub`. The server itself is locked down so only ports 80, 443 and 22 are open, only the users `app` and `dokku` are allowed to log in and they must use public/private key encryption - no passwords allowed.
|
36
|
+
|
37
|
+
To test this, it's worth taking a look at [Multipass](https://multipass.run) - a tool from Canonical that lets you create virtual machines (using cloud init files) on your local machine - meaning you can try out various configurations without spending money at a hosting company.
|
24
38
|
|
25
|
-
|
26
|
-
- Installs various necessary packages, plus dokku itself
|
27
|
-
- Sets up the firewall
|
28
|
-
- Creates unix users for each app, adding them to the sudo and docker groups, and setting their authorized_keys files with the given public key
|
29
|
-
- Schedule a `docker system prune` once per week to clean up any dangling images or containers
|
30
|
-
- Configure nginx
|
31
|
-
- Install dokku plugins and run any configuration you have defined
|
32
|
-
- Sets the dokku deployment branch to `main`
|
33
|
-
- Disallows root and passwordless logins over SSH
|
39
|
+
Once you've built a preconfigured virtual machine, we can move on to getting our dokku application installed.
|
34
40
|
|
35
|
-
|
41
|
+
### Installing an application onto the server
|
36
42
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
43
|
+
Move to your application's root folder and create the deploy.yml file (see below). Then use the `app install` command to set dokku up for your first deployment.
|
44
|
+
|
45
|
+
```sh
|
46
|
+
anvil app install
|
47
|
+
```
|
48
|
+
|
49
|
+
This will SSH into the server (or servers if you have multiple) from your config file and:
|
50
|
+
|
51
|
+
- Installs any dokku plugins that you have specified
|
52
|
+
- Tells dokku to create the app
|
53
|
+
- Uses your config file to set the environment variables for the app
|
54
|
+
- Sets some sensible defaults for Nginx and makes sure it proxies correctly to your app
|
55
|
+
- Optionally forwards the correct SSL/TLS headers if your app is behind a load-balancer
|
56
|
+
- Finally it runs the post-installation scripts from your config file, which you can use to configure your plugins
|
57
|
+
|
58
|
+
Next up we deploy the app.
|
59
|
+
|
60
|
+
```sh
|
61
|
+
anvil app deploy
|
62
|
+
```
|
63
|
+
As this is the first deployment, anvil will create git remotes for each host, then do the initial git push. If you have multiple servers configured, these should run in parallel (coming soon). Once each deployment has completed, anvil will SSH in, scale your app and run the post-first-deployment scripts.
|
42
64
|
|
43
|
-
|
65
|
+
You can then use the same `anvil app deploy` command to deploy the app again - but as it knows this isn't the first deployment (as it does not need to create the git remotes), it will run your post-deployment scripts (not post-first-deployment) each time.
|
44
66
|
|
45
|
-
|
46
|
-
|
67
|
+
To change the number of processes (as defined by your Procfile), you can set the `scale` key(s) in your config file and then call:
|
68
|
+
|
69
|
+
```sh
|
70
|
+
anvil app scale
|
71
|
+
```
|
72
|
+
|
73
|
+
(COMING SOON)
|
74
|
+
Finally, if you need to change the values of any environment variables, update your config file and use:
|
75
|
+
|
76
|
+
```sh
|
77
|
+
anvil app configure
|
78
|
+
```
|
47
79
|
|
48
80
|
### Configuration Files
|
49
81
|
|
50
82
|
An Anvil configuration file specifies the configuration for multiple servers and multiple apps. Each server is configured, then each app is installed onto each server.
|
51
83
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
public_key: /home/local-user/.ssh/my-key.pub
|
62
|
-
timezone: Europe/London
|
63
|
-
ports:
|
64
|
-
- 22/tcp
|
65
|
-
- 80/tcp
|
66
|
-
- 443/tcp
|
67
|
-
nginx:
|
68
|
-
forward_proxy_headers: false
|
69
|
-
client_max_body_size: 512m
|
70
|
-
proxy_read_timeout: 60s
|
71
|
-
plugins:
|
72
|
-
cron-restart:
|
73
|
-
url: https://github.com/dokku/dokku-cron-restart.git
|
74
|
-
maintenance:
|
75
|
-
url: https://github.com/dokku/dokku-maintenance.git
|
76
|
-
redis:
|
77
|
-
url: https://github.com/dokku/dokku-redis.git
|
78
|
-
memcached:
|
79
|
-
url: https://github.com/dokku/dokku-memcached.git
|
80
|
-
letsencrypt:
|
81
|
-
url: https://github.com/dokku/dokku-letsencrypt.git
|
82
|
-
config:
|
83
|
-
- set --global email ssl-admin@mycompany.com
|
84
|
-
- cronjob --add
|
85
|
-
apps:
|
86
|
-
first_app:
|
87
|
-
hostname: first_app.example.com
|
88
|
-
port: 3000
|
89
|
-
environment:
|
90
|
-
- ENV_VAR=value
|
91
|
-
- ENV_VAR2=value2
|
92
|
-
- RAILS_ENV=production
|
93
|
-
secrets: secrets.yml
|
94
|
-
resource_limit: 2048m
|
95
|
-
scale: web=2 worker=1
|
96
|
-
plugins:
|
97
|
-
cron-restart:
|
98
|
-
- set first_app schedule '0 3 * * *'
|
99
|
-
redis:
|
100
|
-
- create first_app_redis_db
|
101
|
-
- link first_app_redis_db first_app
|
102
|
-
memcached:
|
103
|
-
- create first_app_memcached
|
104
|
-
- link first_app_memcached first_app
|
105
|
-
letsencrypt:
|
106
|
-
- set first_app email ssl-admin@mycompany.com
|
107
|
-
- enable first_app
|
108
|
-
second_app:
|
109
|
-
hostname: second_app.example.com
|
110
|
-
port: 3000
|
111
|
-
environment:
|
112
|
-
- ENV_VAR=value
|
113
|
-
- ENV_VAR2=value2
|
114
|
-
- RAILS_ENV=production
|
115
|
-
secrets: secrets.yml
|
116
|
-
resource_limit: 2048m
|
117
|
-
scale: web=2 worker=1
|
118
|
-
plugins:
|
119
|
-
cron-restart:
|
120
|
-
- set second_app schedule '0 3 * * *'
|
121
|
-
letsencrypt:
|
122
|
-
- set second_app email ssl-admin@mycompany.com
|
123
|
-
- enable second_app
|
124
|
-
```
|
125
|
-
`secrets.yml` is an optional additional file containing environment variables that you do not want to check into your source code repository. It is a simple KEY=VALUE format:
|
84
|
+
For now take a look at the two samples in the spec folder - [multi-server](/spec/fixtures/multi-server.config.yml) and [single-server](/spec/fixtures/single-server.config.yml).
|
85
|
+
|
86
|
+
### Secrets
|
87
|
+
|
88
|
+
Finally, you'll probably want to check your deploy.yml file into source control. But you _definitely_ don't want to be storing important secrets - database passwords, encryption keys and so on - where everyone can see them.
|
89
|
+
|
90
|
+
So the `anvil app` commands also allow you to specify secrets, either from another file, or via the command line.
|
91
|
+
|
92
|
+
The secrets are just extra environment variables that are added to the ones defined in your config file - in the format:
|
126
93
|
|
127
94
|
```
|
128
|
-
|
129
|
-
ENCRYPTION_KEY=secretstuff
|
95
|
+
SECRET1=VALUE1 SECRET2=VALUE2
|
130
96
|
```
|
131
97
|
|
98
|
+
You can either specify `--secrets my-secrets-file.env` to load these from a separate file. Or you can load them from stdin.
|
99
|
+
|
100
|
+
For example, I use [Bitwarden](https://bitwarden.com) as my password locker and use the Bitwarden CLI to access my secrets. The CLI is installed through homebrew, I then authenticate and can use a command like:
|
101
|
+
|
102
|
+
```sh
|
103
|
+
bw get notes secrets@myapp.com | anvil app install deploy.myapp.yml -S
|
104
|
+
```
|
105
|
+
I have the environment variables for myapp.com stored in Bitwarden as a secure note with the title "secrets@myapp.com". So `bw get notes secrets@myapp.com` loads them from my vault and pipes them to the `anvil app install` command. The anvil command is using the `-S` (or `--secrets-stdin`) option which means it will read the information piped in by bitwarden. So, once decrypted, the confidential data never touches a disk until it gets written into the dokku app configuration on the server.
|
132
106
|
|
133
107
|
## Contributing
|
134
108
|
|
@@ -0,0 +1,50 @@
|
|
1
|
+
#cloud-config
|
2
|
+
users:
|
3
|
+
- name: %{USER}
|
4
|
+
groups: users, admin, docker
|
5
|
+
sudo: ALL=(ALL) NOPASSWD:ALL
|
6
|
+
shell: /bin/bash
|
7
|
+
ssh_authorized_keys:
|
8
|
+
- %{PUBLIC_KEY}
|
9
|
+
packages:
|
10
|
+
- fail2ban
|
11
|
+
- ufw
|
12
|
+
- wget
|
13
|
+
- apt-transport-https
|
14
|
+
- ca-certificates
|
15
|
+
- curl
|
16
|
+
- gpg-agent
|
17
|
+
- software-properties-common
|
18
|
+
package_update: true
|
19
|
+
package_upgrade: true
|
20
|
+
runcmd:
|
21
|
+
# General server setup
|
22
|
+
- timedatectl set-timezone UTC
|
23
|
+
- echo "${USER}:${USER}" | chpasswd
|
24
|
+
# Prepare for Docker
|
25
|
+
- sudo install -m 0755 -d /etc/apt/keyrings
|
26
|
+
- curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
27
|
+
- sudo chmod a+r /etc/apt/keyrings/docker.gpg
|
28
|
+
- echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
|
29
|
+
# Install docker
|
30
|
+
- apt-get update
|
31
|
+
- apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
32
|
+
# Fail2Ban setup
|
33
|
+
- printf "[sshd]\nenabled = true\nbanaction = iptables-multiport" > /etc/fail2ban/jail.local
|
34
|
+
- systemctl enable fail2ban
|
35
|
+
# UFW and SSH setup
|
36
|
+
- ufw allow 22/tcp
|
37
|
+
- ufw allow 80/tcp
|
38
|
+
- ufw allow 443/tcp
|
39
|
+
- ufw enable
|
40
|
+
# Harden SSH
|
41
|
+
- sed -i -e '/^\(#\|\)PermitRootLogin/s/^.*$/PermitRootLogin no/' /etc/ssh/sshd_config
|
42
|
+
- sed -i -e '/^\(#\|\)PasswordAuthentication/s/^.*$/PasswordAuthentication no/' /etc/ssh/sshd_config
|
43
|
+
- sed -i -e '/^\(#\|\)X11Forwarding/s/^.*$/X11Forwarding no/' /etc/ssh/sshd_config
|
44
|
+
- sed -i -e '/^\(#\|\)MaxAuthTries/s/^.*$/MaxAuthTries 2/' /etc/ssh/sshd_config
|
45
|
+
- sed -i -e '/^\(#\|\)AllowTcpForwarding/s/^.*$/AllowTcpForwarding no/' /etc/ssh/sshd_config
|
46
|
+
- sed -i -e '/^\(#\|\)AllowAgentForwarding/s/^.*$/AllowAgentForwarding no/' /etc/ssh/sshd_config
|
47
|
+
- sed -i -e '/^\(#\|\)AuthorizedKeysFile/s/^.*$/AuthorizedKeysFile .ssh\/authorized_keys/' /etc/ssh/sshd_config
|
48
|
+
- sed -i '$a AllowUsers %{USER} dokku' /etc/ssh/sshd_config
|
49
|
+
# And we're done
|
50
|
+
- reboot
|
@@ -11,11 +11,29 @@ packages:
|
|
11
11
|
- ufw
|
12
12
|
- wget
|
13
13
|
- apt-transport-https
|
14
|
+
- ca-certificates
|
15
|
+
- curl
|
16
|
+
- gpg-agent
|
17
|
+
- software-properties-common
|
14
18
|
package_update: true
|
15
19
|
package_upgrade: true
|
16
20
|
runcmd:
|
17
21
|
# General server setup
|
18
22
|
- timedatectl set-timezone UTC
|
23
|
+
- echo "${USER}:${USER}" | chpasswd
|
24
|
+
# Prepare for Docker
|
25
|
+
- sudo install -m 0755 -d /etc/apt/keyrings
|
26
|
+
- curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
27
|
+
- sudo chmod a+r /etc/apt/keyrings/docker.gpg
|
28
|
+
- echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
|
29
|
+
# Install docker
|
30
|
+
- apt-get update
|
31
|
+
- apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
32
|
+
# Install dokku
|
33
|
+
- echo "dokku dokku/vhost_enable boolean true" | sudo debconf-set-selections
|
34
|
+
- wget https://dokku.com/install/v0.30.7/bootstrap.sh && sudo DOKKU_TAG=v0.30.7 bash bootstrap.sh
|
35
|
+
- cat /home/app/.ssh/authorized_keys | dokku ssh-keys:add admin
|
36
|
+
- dokku git:set --global deploy-branch main
|
19
37
|
# Fail2Ban setup
|
20
38
|
- printf "[sshd]\nenabled = true\nbanaction = iptables-multiport" > /etc/fail2ban/jail.local
|
21
39
|
- systemctl enable fail2ban
|
@@ -33,16 +51,6 @@ runcmd:
|
|
33
51
|
- sed -i -e '/^\(#\|\)AllowAgentForwarding/s/^.*$/AllowAgentForwarding no/' /etc/ssh/sshd_config
|
34
52
|
- sed -i -e '/^\(#\|\)AuthorizedKeysFile/s/^.*$/AuthorizedKeysFile .ssh\/authorized_keys/' /etc/ssh/sshd_config
|
35
53
|
- sed -i '$a AllowUsers %{USER} dokku' /etc/ssh/sshd_config
|
36
|
-
#
|
37
|
-
- echo "dokku dokku/vhost_enable boolean true" | sudo debconf-set-selections
|
38
|
-
- wget https://dokku.com/install/v0.30.7/bootstrap.sh && sudo DOKKU_TAG=v0.30.7 bash bootstrap.sh
|
39
|
-
- cat /home/%{USER}/.ssh/authorized_keys | dokku ssh-keys:add admin
|
40
|
-
- dokku plugin:install https://github.com/dokku/dokku-cron-restart.git cron-restart
|
41
|
-
- dokku plugin:install https://github.com/dokku/dokku-maintenance.git maintenance
|
42
|
-
- dokku plugin:install https://github.com/dokku/dokku-redis.git redis
|
43
|
-
- dokku plugin:install https://github.com/dokku/dokku-mariadb.git mariadb
|
44
|
-
- dokku plugin:install https://github.com/dokku/dokku-memcached.git memcached
|
45
|
-
- dokku plugin:install https://github.com/dokku/dokku-letsencrypt.git letsencrypt
|
46
|
-
- dokku config:set --global DOKKU_LETSENCRYPT_EMAIL=sysadmin@echodek.co
|
47
|
-
- dokku git:set --global deploy-branch main
|
54
|
+
# And we're done
|
48
55
|
- reboot
|
56
|
+
|
@@ -10,13 +10,13 @@ packages:
|
|
10
10
|
- fail2ban
|
11
11
|
- ufw
|
12
12
|
- wget
|
13
|
-
- memcached
|
14
13
|
- logrotate
|
15
14
|
package_update: true
|
16
15
|
package_upgrade: true
|
17
16
|
runcmd:
|
18
17
|
# General server setup
|
19
18
|
- timedatectl set-timezone UTC
|
19
|
+
- echo "${USER}:${USER}" | chpasswd
|
20
20
|
# Fail2Ban setup
|
21
21
|
- printf "[sshd]\nenabled = true\nbanaction = iptables-multiport" > /etc/fail2ban/jail.local
|
22
22
|
- systemctl enable fail2ban
|
@@ -34,6 +34,7 @@ runcmd:
|
|
34
34
|
- sed -i -e '/^\(#\|\)AuthorizedKeysFile/s/^.*$/AuthorizedKeysFile .ssh\/authorized_keys/' /etc/ssh/sshd_config
|
35
35
|
- sed -i '$a AllowUsers %{USER}' /etc/ssh/sshd_config
|
36
36
|
# Set up memcached
|
37
|
+
- apt-get -y install memcached
|
37
38
|
- sed -i 's/-m 64/-m 512/g' /etc/memcached.conf
|
38
39
|
- sed -i 's/-l 127.0.0.1/-l 0.0.0.0/g' /etc/memcached.conf
|
39
40
|
- systemctl restart memcached.service
|
@@ -16,10 +16,11 @@ package_upgrade: true
|
|
16
16
|
runcmd:
|
17
17
|
# General server setup
|
18
18
|
- timedatectl set-timezone UTC
|
19
|
+
- echo "${USER}:${USER}" | chpasswd
|
19
20
|
# Install MySQL
|
20
21
|
- echo "mysql-server mysql-server/root_password password root" | sudo debconf-set-selections
|
21
22
|
- echo "mysql-server mysql-server/root_password_again password root" | sudo debconf-set-selections
|
22
|
-
-
|
23
|
+
- apt-get -y install mysql-server
|
23
24
|
- |
|
24
25
|
cat >> /etc/mysql/mysql.conf.d/utf8.cnf << CONF
|
25
26
|
[client]
|
@@ -10,14 +10,13 @@ packages:
|
|
10
10
|
- fail2ban
|
11
11
|
- ufw
|
12
12
|
- wget
|
13
|
-
- docker.io
|
14
|
-
- docker-compose
|
15
13
|
- apt-transport-https
|
16
14
|
package_update: true
|
17
15
|
package_upgrade: true
|
18
16
|
runcmd:
|
19
17
|
# General server setup
|
20
18
|
- timedatectl set-timezone UTC
|
19
|
+
- echo "${USER}:${USER}" | chpasswd
|
21
20
|
# Prepare for OpenSearch
|
22
21
|
- swapoff -a
|
23
22
|
- echo "vm.max_map_count=262144" > /etc/sysctl.d/98-opensearch.conf
|
@@ -39,6 +38,14 @@ runcmd:
|
|
39
38
|
- sed -i -e '/^\(#\|\)AllowAgentForwarding/s/^.*$/AllowAgentForwarding no/' /etc/ssh/sshd_config
|
40
39
|
- sed -i -e '/^\(#\|\)AuthorizedKeysFile/s/^.*$/AuthorizedKeysFile .ssh\/authorized_keys/' /etc/ssh/sshd_config
|
41
40
|
- sed -i '$a AllowUsers %{USER}' /etc/ssh/sshd_config
|
41
|
+
# Install docker
|
42
|
+
- apt-get install -y ca-certificates curl gnupg
|
43
|
+
- install -m 0755 -d /etc/apt/keyrings
|
44
|
+
- curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
45
|
+
- chmod a+r /etc/apt/keyrings/docker.gpg
|
46
|
+
- echo "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
|
47
|
+
- apt-get update
|
48
|
+
- apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
42
49
|
# OpenSearch setup
|
43
50
|
- mkdir -p /etc/opensearch
|
44
51
|
- docker pull opensearchproject/opensearch:latest
|
@@ -55,7 +62,7 @@ runcmd:
|
|
55
62
|
- node.name=search_db
|
56
63
|
- bootstrap.memory_lock=true
|
57
64
|
- plugins.security.disabled=true
|
58
|
-
- "OPENSEARCH_JAVA_OPTS=-
|
65
|
+
- "OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx3184m"
|
59
66
|
ulimits:
|
60
67
|
memlock:
|
61
68
|
soft: -1
|
@@ -71,16 +78,18 @@ runcmd:
|
|
71
78
|
volumes:
|
72
79
|
opensearch_data:
|
73
80
|
EOF
|
81
|
+
- cd /etc/opensearch && docker compose build
|
74
82
|
- |
|
75
83
|
cat >> /etc/systemd/system/opensearch.service << EOF
|
76
|
-
|
84
|
+
[Unit]
|
85
|
+
Description=OpenSearch
|
77
86
|
Requires=docker.service
|
78
87
|
After=docker.service
|
79
88
|
[Service]
|
80
89
|
WorkingDirectory=/etc/opensearch
|
81
90
|
Restart=always
|
82
|
-
ExecStart=/usr/bin/docker
|
83
|
-
ExecStop=/usr/bin/docker
|
91
|
+
ExecStart=/usr/bin/docker compose up
|
92
|
+
ExecStop=/usr/bin/docker compose down
|
84
93
|
[Install]
|
85
94
|
WantedBy=multi-user.target
|
86
95
|
EOF
|
@@ -10,13 +10,13 @@ packages:
|
|
10
10
|
- fail2ban
|
11
11
|
- ufw
|
12
12
|
- wget
|
13
|
-
- redis-server
|
14
13
|
- logrotate
|
15
14
|
package_update: true
|
16
15
|
package_upgrade: true
|
17
16
|
runcmd:
|
18
17
|
# General server setup
|
19
18
|
- timedatectl set-timezone UTC
|
19
|
+
- echo "${USER}:${USER}" | chpasswd
|
20
20
|
# Fail2Ban setup
|
21
21
|
- printf "[sshd]\nenabled = true\nbanaction = iptables-multiport" > /etc/fail2ban/jail.local
|
22
22
|
- systemctl enable fail2ban
|
@@ -34,6 +34,7 @@ runcmd:
|
|
34
34
|
- sed -i -e '/^\(#\|\)AuthorizedKeysFile/s/^.*$/AuthorizedKeysFile .ssh\/authorized_keys/' /etc/ssh/sshd_config
|
35
35
|
- sed -i '$a AllowUsers %{USER}' /etc/ssh/sshd_config
|
36
36
|
# Set up Redis
|
37
|
+
- apt-get -y install redis-server
|
37
38
|
- sed -i 's/supervised no/supervised systemd/g' /etc/redis/redis.conf
|
38
39
|
- sed -i 's/bind 127.0.0.1 ::1/# bind 127.0.0.1 ::1/g' /etc/redis/redis.conf
|
39
40
|
- sed -i 's/protected-mode yes/protected-mode no/g' /etc/redis/redis.conf
|
@@ -0,0 +1 @@
|
|
1
|
+
185f01d498e635d91fcbc77ae60a47529b68f927302c67dc7b052a4b190d6aa1197c9c7d46d9626f927ea80b5d40162ed3e86177d63d5dbcd93b957dbf4238b7
|
@@ -0,0 +1 @@
|
|
1
|
+
11a59b33098151fd6205adbd24c410acd58168066dc2942b93feb601557f527fecce250002d6157bacf0007a546a4a23abdc219f269bc73820236cae738b63a0
|
@@ -0,0 +1 @@
|
|
1
|
+
fb8d74684e40d48b82c6ad58503e52b035a76fe4f534a8fcb5ec043227af442035ef5f0d1a845cb8e8bebc3556bfcb4718fca26dcb53b4f816f76c1990f0c4d5
|
@@ -0,0 +1 @@
|
|
1
|
+
5c4b010036ad155590705bf75b564c167513f342524abf34073080de20ccdf2b2c0ef4671f38dccb53781603f7373537436c8a6bbc7a43a5eb33c3fabbd1821d
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Anvil
|
4
|
+
class App
|
5
|
+
require_relative "host_deployer"
|
6
|
+
class Deploy < Struct.new(:configuration)
|
7
|
+
include ConfigurationReader
|
8
|
+
def call
|
9
|
+
branch = `git rev-parse --abbrev-ref HEAD`.strip
|
10
|
+
hosts.each do |host|
|
11
|
+
HostDeployer.new(configuration, host.to_s.strip, branch).call
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "standard_procedure/async"
|
4
|
+
module Anvil
|
5
|
+
require_relative "../logger"
|
6
|
+
require_relative "../ssh_executor"
|
7
|
+
require_relative "../configuration_reader"
|
8
|
+
class App
|
9
|
+
class HostDeployer < Struct.new(:configuration, :host, :branch)
|
10
|
+
include StandardProcedure::Async::Actor
|
11
|
+
include Anvil::ConfigurationReader
|
12
|
+
|
13
|
+
def call
|
14
|
+
first_deployment = !git_remote_exists?
|
15
|
+
if first_deployment
|
16
|
+
switch_off_downtime_checks
|
17
|
+
create_git_remote
|
18
|
+
end
|
19
|
+
|
20
|
+
do_git_push
|
21
|
+
if first_deployment
|
22
|
+
switch_on_downtime_checks
|
23
|
+
run_after_first_deployment_scripts
|
24
|
+
scale_processes
|
25
|
+
else
|
26
|
+
run_after_deployment_scripts
|
27
|
+
end
|
28
|
+
logger.info "Deployment for #{host} complete"
|
29
|
+
end
|
30
|
+
|
31
|
+
protected
|
32
|
+
|
33
|
+
def git_remote_exists?
|
34
|
+
`git remote show`.split("\n").include? host
|
35
|
+
end
|
36
|
+
|
37
|
+
def switch_off_downtime_checks
|
38
|
+
Anvil::SshExecutor.new(host, user_for(host), logger).call do |ssh|
|
39
|
+
ssh.exec! "dokku checks:disable app worker,web"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def create_git_remote
|
44
|
+
logger.info `git remote add #{host} dokku@#{host}:/app`
|
45
|
+
end
|
46
|
+
|
47
|
+
def do_git_push
|
48
|
+
logger.info `git push #{host} #{branch}:main`
|
49
|
+
end
|
50
|
+
|
51
|
+
def switch_on_downtime_checks
|
52
|
+
Anvil::SshExecutor.new(host, user_for(host), logger).call do |ssh|
|
53
|
+
ssh.exec! "dokku checks:enable app web"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def run_after_first_deployment_scripts
|
58
|
+
Anvil::SshExecutor.new(host, user_for(host), logger).call do |ssh|
|
59
|
+
(configuration_for(host).dig("scripts")&.dig("after_first_deploy") || []).each do |script|
|
60
|
+
ssh.exec! script, "run_after_install_scripts"
|
61
|
+
end
|
62
|
+
(configuration_for_app.dig("scripts")&.dig("after_first_deploy") || []).each do |script|
|
63
|
+
ssh.exec! script, "run_after_install_scripts"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def scale_processes
|
69
|
+
Anvil::App::HostScaler.new(configuration, host).call
|
70
|
+
end
|
71
|
+
|
72
|
+
def run_after_deployment_scripts
|
73
|
+
Anvil::SshExecutor.new(host, user_for(host), logger).call do |ssh|
|
74
|
+
(configuration_for(host).dig("scripts")&.dig("after_deploy") || []).each do |script|
|
75
|
+
ssh.exec! script, "run_after_install_scripts"
|
76
|
+
end
|
77
|
+
(configuration_for_app.dig("scripts")&.dig("after_deploy") || []).each do |script|
|
78
|
+
ssh.exec! script, "run_after_install_scripts"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def logger
|
84
|
+
@logger ||= Anvil::Logger.new(host)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -5,21 +5,30 @@ module Anvil
|
|
5
5
|
require_relative "../logger"
|
6
6
|
require_relative "../ssh_executor"
|
7
7
|
require_relative "env"
|
8
|
+
require_relative "../configuration_reader"
|
8
9
|
class App
|
9
10
|
class HostInstaller < Struct.new(:configuration, :host, :secrets)
|
10
11
|
include StandardProcedure::Async::Actor
|
12
|
+
include Anvil::ConfigurationReader
|
11
13
|
|
12
|
-
|
14
|
+
def call
|
13
15
|
Anvil::SshExecutor.new(host, user_for(host), logger).call do |ssh|
|
16
|
+
install_plugins ssh
|
14
17
|
create_app ssh
|
15
18
|
set_environment ssh
|
16
19
|
set_dokku_options ssh
|
17
|
-
|
20
|
+
run_after_install_scripts ssh
|
18
21
|
end
|
19
22
|
end
|
20
23
|
|
21
24
|
protected
|
22
25
|
|
26
|
+
def install_plugins ssh
|
27
|
+
(configuration_for_app.fetch("plugins") | []).each do |plugin|
|
28
|
+
ssh.exec! "sudo dokku plugin:install https://github.com/dokku/dokku-#{plugin}.git #{plugin}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
23
32
|
def create_app ssh
|
24
33
|
ssh.exec! "dokku apps:create app", "create_app"
|
25
34
|
end
|
@@ -32,22 +41,27 @@ module Anvil
|
|
32
41
|
ssh.exec! "dokku docker-options:add app run \"--add-host=host.docker.internal:host-gateway\"", "set_dokku_options"
|
33
42
|
ssh.exec! "dokku domains:set app #{configuration_for_app["domain"]}", "set_dokku_options"
|
34
43
|
ssh.exec! "dokku proxy:ports-add app http:80:#{configuration_for_app["port"]}", "set_dokku_options"
|
35
|
-
ssh.exec! "dokku nginx:set app client-max-body-size
|
36
|
-
ssh.exec! "dokku nginx:set app proxy-read-timeout
|
44
|
+
ssh.exec! "dokku nginx:set app client-max-body-size #{configuration_for_app["nginx"]["client_max_body_size"]}", "set_dokku_options"
|
45
|
+
ssh.exec! "dokku nginx:set app proxy-read-timeout #{configuration_for_app["nginx"]["proxy_read_timeout"]}", "set_dokku_options"
|
46
|
+
if configuration_for_app["load_balancer"]
|
47
|
+
ssh.exec! "dokku nginx:set app x-forwarded-for-value \"$http_x_forwarded_for\"", "set_dokku_options"
|
48
|
+
ssh.exec! "dokku nginx:set app x-forwarded-port-value \"$http_x_forwarded_port\"", "set_dokku_options"
|
49
|
+
ssh.exec! "dokku nginx:set app x-forwarded-proto-value \"$http_x_forwarded_proto\"", "set_dokku_options"
|
50
|
+
end
|
37
51
|
ssh.exec! "dokku proxy:build-config app", "set_dokku_options"
|
38
52
|
end
|
39
53
|
|
40
|
-
def
|
41
|
-
|
42
|
-
ssh.exec! script, "
|
54
|
+
def run_after_install_scripts ssh
|
55
|
+
(configuration_for(host).dig("scripts")&.dig("after_install") || []).each do |script|
|
56
|
+
ssh.exec! script, "run_after_install_scripts"
|
43
57
|
end
|
44
|
-
|
45
|
-
ssh.exec! script, "
|
58
|
+
(configuration_for_app.dig("scripts")&.dig("after_install") || []).each do |script|
|
59
|
+
ssh.exec! script, "run_after_install_scripts"
|
46
60
|
end
|
47
61
|
end
|
48
62
|
|
49
63
|
def logger
|
50
|
-
@logger ||= Anvil::Logger.new(
|
64
|
+
@logger ||= Anvil::Logger.new(host)
|
51
65
|
end
|
52
66
|
end
|
53
67
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "standard_procedure/async"
|
4
|
+
module Anvil
|
5
|
+
require_relative "../logger"
|
6
|
+
require_relative "../ssh_executor"
|
7
|
+
require_relative "../configuration_reader"
|
8
|
+
class App
|
9
|
+
class HostScaler < Struct.new(:configuration, :host)
|
10
|
+
include StandardProcedure::Async::Actor
|
11
|
+
include Anvil::ConfigurationReader
|
12
|
+
|
13
|
+
def call
|
14
|
+
scale_processes
|
15
|
+
end
|
16
|
+
|
17
|
+
protected
|
18
|
+
|
19
|
+
def scale_processes
|
20
|
+
scale = configuration_for(host).dig("scale") || configuration_for_app.dig("scale") || "web=1"
|
21
|
+
Anvil::SshExecutor.new(host, user_for(host), logger).call do |ssh|
|
22
|
+
ssh.exec! "dokku ps:scale app #{scale}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def logger
|
27
|
+
@logger ||= Anvil::Logger.new(host)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Anvil
|
4
|
+
class App
|
5
|
+
require_relative "host_scaler"
|
6
|
+
class Scale < Struct.new(:configuration)
|
7
|
+
include ConfigurationReader
|
8
|
+
def call
|
9
|
+
hosts.each do |host|
|
10
|
+
HostScaler.new(configuration, host.to_s.strip).call
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/anvil/app.rb
CHANGED
@@ -6,6 +6,9 @@ require "yaml"
|
|
6
6
|
module Anvil
|
7
7
|
class App < Anvil::SubCommandBase
|
8
8
|
require_relative "app/env"
|
9
|
+
require_relative "app/install"
|
10
|
+
require_relative "app/deploy"
|
11
|
+
require_relative "app/scale"
|
9
12
|
|
10
13
|
desc "env /path/to/config.yml", "Generate environment variables for an app"
|
11
14
|
long_desc <<-DESC
|
@@ -48,6 +51,34 @@ module Anvil
|
|
48
51
|
Anvil::App::Install.new(configuration, secrets).call
|
49
52
|
end
|
50
53
|
|
54
|
+
desc "deploy /path/to/config.yml", "Deploy an app"
|
55
|
+
long_desc <<-DESC
|
56
|
+
Deploy an app on the hosts specified in the configuration.
|
57
|
+
|
58
|
+
First it checks to see if a git remote exists for each host.
|
59
|
+
|
60
|
+
If not, this counts as a first deployment and it creates the git remote
|
61
|
+
|
62
|
+
Then, whether first deployment or not, it does a `git push` of the current branch to main on the remote.
|
63
|
+
|
64
|
+
Finally, if this is the first deployment, it runs the "after_first_deployment" scripts, otherwise it runs the "after_deployment" scripts.
|
65
|
+
DESC
|
66
|
+
def deploy filename = "deploy.yml"
|
67
|
+
configuration = YAML.load_file(filename)
|
68
|
+
Anvil::App::Deploy.new(configuration).call
|
69
|
+
end
|
70
|
+
|
71
|
+
desc "scale /path/to/config.yml", "Scale an app"
|
72
|
+
long_desc <<-DESC
|
73
|
+
Scale a previously deployed app, using the scale values from the config file.
|
74
|
+
|
75
|
+
The scale can either be set per host or per app (with host settings taking priority).
|
76
|
+
DESC
|
77
|
+
def scale filename = "deploy.yml"
|
78
|
+
configuration = YAML.load_file(filename)
|
79
|
+
Anvil::App::Scale.new(configuration).call
|
80
|
+
end
|
81
|
+
|
51
82
|
protected
|
52
83
|
|
53
84
|
def read_secrets(filename: nil, stdin: false)
|
data/lib/anvil/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: standard-procedure-anvil
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rahoul Baruah
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-07-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -110,19 +110,27 @@ files:
|
|
110
110
|
- LICENSE.txt
|
111
111
|
- README.md
|
112
112
|
- Rakefile
|
113
|
-
- assets/cloudinit/
|
114
|
-
- assets/cloudinit/dokku.
|
115
|
-
- assets/cloudinit/memcached.
|
116
|
-
- assets/cloudinit/mysql.
|
117
|
-
- assets/cloudinit/opensearch.
|
118
|
-
- assets/cloudinit/redis.
|
113
|
+
- assets/cloudinit/docker.yml
|
114
|
+
- assets/cloudinit/dokku.yml
|
115
|
+
- assets/cloudinit/memcached.yml
|
116
|
+
- assets/cloudinit/mysql.yml
|
117
|
+
- assets/cloudinit/opensearch.yml
|
118
|
+
- assets/cloudinit/redis.yml
|
119
119
|
- checksums/standard-procedure-anvil-0.1.4.gem.sha512
|
120
|
+
- checksums/standard-procedure-anvil-0.1.5.gem.sha512
|
121
|
+
- checksums/standard-procedure-anvil-0.1.6.gem.sha512
|
122
|
+
- checksums/standard-procedure-anvil-0.1.7.gem.sha512
|
123
|
+
- checksums/standard-procedure-anvil-0.2.0.gem.sha512
|
120
124
|
- exe/anvil
|
121
125
|
- lib/anvil.rb
|
122
126
|
- lib/anvil/app.rb
|
127
|
+
- lib/anvil/app/deploy.rb
|
123
128
|
- lib/anvil/app/env.rb
|
129
|
+
- lib/anvil/app/host_deployer.rb
|
124
130
|
- lib/anvil/app/host_installer.rb
|
131
|
+
- lib/anvil/app/host_scaler.rb
|
125
132
|
- lib/anvil/app/install.rb
|
133
|
+
- lib/anvil/app/scale.rb
|
126
134
|
- lib/anvil/cli.rb
|
127
135
|
- lib/anvil/cloudinit.rb
|
128
136
|
- lib/anvil/cloudinit/generator.rb
|
@@ -1,126 +0,0 @@
|
|
1
|
-
#cloud-config
|
2
|
-
users:
|
3
|
-
- name: %{USER}
|
4
|
-
groups: users, admin, docker
|
5
|
-
sudo: ALL=(ALL) NOPASSWD:ALL
|
6
|
-
shell: /bin/bash
|
7
|
-
ssh_authorized_keys:
|
8
|
-
- %{PUBLIC_KEY}
|
9
|
-
packages:
|
10
|
-
- fail2ban
|
11
|
-
- ufw
|
12
|
-
- wget
|
13
|
-
- apt-transport-https
|
14
|
-
- docker.io
|
15
|
-
- docker-compose
|
16
|
-
- mysql-client
|
17
|
-
- libmysqlclient-dev
|
18
|
-
package_update: true
|
19
|
-
package_upgrade: true
|
20
|
-
runcmd:
|
21
|
-
# General server setup
|
22
|
-
- timedatectl set-timezone UTC
|
23
|
-
# Prepare for OpenSearch
|
24
|
-
- swapoff -a
|
25
|
-
- echo "vm.max_map_count=262144" > /etc/sysctl.d/98-opensearch.conf
|
26
|
-
- sysctl -p /etc/sysctl.d/98-opensearch.conf
|
27
|
-
# Install MySQL
|
28
|
-
- echo "mysql-server mysql-server/root_password password root" | sudo debconf-set-selections
|
29
|
-
- echo "mysql-server mysql-server/root_password_again password root" | sudo debconf-set-selections
|
30
|
-
- sudo apt-get -y install mysql-server
|
31
|
-
- |
|
32
|
-
cat >> /etc/mysql/mysql.conf.d/utf8.cnf << CONF
|
33
|
-
[client]
|
34
|
-
default-character-set=utf8mb4
|
35
|
-
|
36
|
-
[mysql]
|
37
|
-
default-character-set=utf8mb4
|
38
|
-
|
39
|
-
[mysqld]
|
40
|
-
init_connect='SET collation_connection = utf8mb4_unicode_ci'
|
41
|
-
init_connect='SET NAMES utf8mb4'
|
42
|
-
character-set-server=utf8mb4
|
43
|
-
collation-server=utf8mb4_unicode_ci
|
44
|
-
skip-character-set-client-handshake
|
45
|
-
CONF
|
46
|
-
- sed -i -e '/^\(#\|\)bind-address/s/^.*$/bind-address = 0.0.0.0/' /etc/mysql/mysql.conf.d/mysqld.cnf
|
47
|
-
# Start MySQL
|
48
|
-
- systemctl start mysql.service
|
49
|
-
# Fail2Ban setup
|
50
|
-
- printf "[sshd]\nenabled = true\nbanaction = iptables-multiport" > /etc/fail2ban/jail.local
|
51
|
-
- systemctl enable fail2ban
|
52
|
-
# UFW and SSH setup
|
53
|
-
- ufw allow 22/tcp
|
54
|
-
- ufw allow 80/tcp
|
55
|
-
- ufw allow 443/tcp
|
56
|
-
- ufw enable
|
57
|
-
# Harden SSH
|
58
|
-
- sed -i -e '/^\(#\|\)PermitRootLogin/s/^.*$/PermitRootLogin no/' /etc/ssh/sshd_config
|
59
|
-
- sed -i -e '/^\(#\|\)PasswordAuthentication/s/^.*$/PasswordAuthentication no/' /etc/ssh/sshd_config
|
60
|
-
- sed -i -e '/^\(#\|\)X11Forwarding/s/^.*$/X11Forwarding no/' /etc/ssh/sshd_config
|
61
|
-
- sed -i -e '/^\(#\|\)MaxAuthTries/s/^.*$/MaxAuthTries 2/' /etc/ssh/sshd_config
|
62
|
-
- sed -i -e '/^\(#\|\)AllowTcpForwarding/s/^.*$/AllowTcpForwarding no/' /etc/ssh/sshd_config
|
63
|
-
- sed -i -e '/^\(#\|\)AllowAgentForwarding/s/^.*$/AllowAgentForwarding no/' /etc/ssh/sshd_config
|
64
|
-
- sed -i -e '/^\(#\|\)AuthorizedKeysFile/s/^.*$/AuthorizedKeysFile .ssh\/authorized_keys/' /etc/ssh/sshd_config
|
65
|
-
- sed -i '$a AllowUsers %{USER} dokku' /etc/ssh/sshd_config
|
66
|
-
# Dokku setup
|
67
|
-
- echo "dokku dokku/vhost_enable boolean true" | sudo debconf-set-selections
|
68
|
-
- wget https://dokku.com/install/v0.30.7/bootstrap.sh && sudo DOKKU_TAG=v0.30.7 bash bootstrap.sh
|
69
|
-
- cat /home/%{USER}/.ssh/authorized_keys | dokku ssh-keys:add admin
|
70
|
-
- dokku plugin:install https://github.com/dokku/dokku-cron-restart.git cron-restart
|
71
|
-
- dokku plugin:install https://github.com/dokku/dokku-maintenance.git maintenance
|
72
|
-
- dokku plugin:install https://github.com/dokku/dokku-redis.git redis
|
73
|
-
- dokku plugin:install https://github.com/dokku/dokku-mariadb.git mariadb
|
74
|
-
- dokku plugin:install https://github.com/dokku/dokku-memcached.git memcached
|
75
|
-
- dokku plugin:install https://github.com/dokku/dokku-letsencrypt.git letsencrypt
|
76
|
-
- dokku config:set --global DOKKU_LETSENCRYPT_EMAIL=sysadmin@echodek.co
|
77
|
-
- dokku git:set --global deploy-branch main
|
78
|
-
# OpenSearch setup
|
79
|
-
- mkdir -p /etc/opensearch
|
80
|
-
- docker pull opensearchproject/opensearch:latest
|
81
|
-
- docker pull opensearchproject/opensearch-dashboards:latest
|
82
|
-
- |
|
83
|
-
cat >> /etc/opensearch/docker-compose.yml << EOF
|
84
|
-
version: '3'
|
85
|
-
services:
|
86
|
-
search_db:
|
87
|
-
image: opensearchproject/opensearch:latest
|
88
|
-
container_name: search_db
|
89
|
-
environment:
|
90
|
-
- discovery.type=single-node
|
91
|
-
- node.name=search_db
|
92
|
-
- bootstrap.memory_lock=true
|
93
|
-
- plugins.security.disabled=true
|
94
|
-
- "OPENSEARCH_JAVA_OPTS=-Xms2048m -Xmx2048m"
|
95
|
-
ulimits:
|
96
|
-
memlock:
|
97
|
-
soft: -1
|
98
|
-
hard: -1
|
99
|
-
nofile:
|
100
|
-
soft: 65536
|
101
|
-
hard: 65536
|
102
|
-
volumes:
|
103
|
-
- opensearch_data:/usr/share/opensearch/data
|
104
|
-
ports:
|
105
|
-
- 9200:9200
|
106
|
-
- 9600:9600
|
107
|
-
volumes:
|
108
|
-
opensearch_data:
|
109
|
-
EOF
|
110
|
-
- |
|
111
|
-
cat >> /etc/systemd/system/opensearch.service << EOF
|
112
|
-
Description=OpenSearch container
|
113
|
-
Requires=docker.service
|
114
|
-
After=docker.service
|
115
|
-
[Service]
|
116
|
-
WorkingDirectory=/etc/opensearch
|
117
|
-
Restart=always
|
118
|
-
ExecStart=/usr/bin/docker-compose up
|
119
|
-
ExecStop=/usr/bin/docker-compose down
|
120
|
-
[Install]
|
121
|
-
WantedBy=multi-user.target
|
122
|
-
EOF
|
123
|
-
- systemctl daemon-reload
|
124
|
-
- systemctl enable opensearch.service
|
125
|
-
- service opensearch start
|
126
|
-
- reboot
|