Development on PaaS with dokku heroku - mavenea/mavencrm GitHub Wiki

dokku prep

  • install dokku on the host or use vagrant for local dev.

the following plugins are useful and used by our configuration

**docker-direct**: dokku plugin to issue docker commands directly
dokku plugin:install https://github.com/josegonzalez/dokku-docker-direct.git docker-direct

**require**: dokku plugin to setup all the requirement for your app on push
dokku plugin:install https://github.com/crisward/dokku-require.git require
**memcached**
sudo dokku plugin:install https://github.com/dokku/dokku-memcached.git memcached
**rabbitmq**
sudo dokku plugin:install https://github.com/dokku/dokku-rabbitmq.git rabbitmq
**mysql**
sudo dokku plugin:install https://github.com/dokku/dokku-mysql.git mysql

# useful for development environment
**nuke**: stop all running containers, then delete all containers and images
dokku plugin:install https://github.com/josegonzalez/dokku-nuke.git nuke


**apt**: Inject deb packages into dokku based on files in project
sudo dokku plugin:install https://github.com/dokku-community/dokku-apt apt

#set mode to dokku_dev as defined in app.json. default is `dokku`
dokku require:mode dokku_dev

example for local dev.

  1. install dokku with vagrant. make sure that port 8080 and port 22 are free on the host.
git clone https://github.com/dokku/dokku.git
vagrant up
  1. ssh to the running machine. you can use vagrant ssh

service forwarding is running on the maching on port 2222 which is forwarded to the dokku virtual machine ssh server listening on port 22. the service is listening only on loopback interface, so this means that dokku cannot be accessed from any other machine using ssh. If we want to ssh from a different machine the virtualbox port forwarding rules need to be changed and allow this. To do this remove the loopback IP Address from Host Network Manager of the VirtualBox NAT adapter port forwarding rules for the dokku virtual machine.

  1. get the private_key created during installation and add it to ssh-agent or use it directly when ssh to the machine. Note: the machine public key usually at ~/.ssh/id_rsa.pub should already be copied to the machine if file exists, however, in my case this did not happen for some reason.
vagrant ssh-config dokku

IdentityFile is the path to the automatically generated private key which is already installed on the dokku virtual machine under ~/.ssh/authorized_keys. We can use the generated private key to connect to the host by either adding to the local ssh-agent (recommended) using ssh-add /path/to/identity/file or by providing the path to the private key with ssh command. You can also copy the key to the ~/.ssh directory and use ssh-add with no arguments - it automatically adds all keys in ~/.ssh to the keystore. I prefer to use a single set of keys rather than manage different service keys, so I use my own public/private key pairs for each machine I use.

User is the user to use for ssh. The user name is vagrant in this case.

  1. ssh to the host ssh -i /path/to/identity/file/ [email protected] or if you added the IdentityFile to ssh-agent then just simply ssh [email protected]. The same key is also automatically added to dokku:ssh-keys to enable ssh remote git push.

verify ssh-keys are added to dokku using

dokku ssh-keys:list

other way of connecting from the local machine is using vagrant ssh from the same folder. if need to copy another ssh public key, login using vagrant ssh and then copy the new public key to ~/.ssh/authorized_keys then run

# usually your key is already available under the current user's `~/.ssh/authorized_keys` file
# the name admin is significant check dokku docs
cat ~/.ssh/authorized_keys | sudo dokku ssh-keys:add admin
  1. enable global vhosts and domain. During installation domain is already configured to dokku.me.

Verify domain is configured

dokku domains:report --global
=====> Global domains information
       Domains global enabled:        true
       Domains global vhosts:         dokku.me

if not dokku domains:set-global dokku.me

Tip: the domain dokku.me is actually internet resolvable domain name! It is a sneaky turnkey solution for getting your local machine up and running in no time without having to mess with hosts file. In fact it maps any host (that is, *) to 10.0.0.2 which is usually the host dokku built when using vagrant up command :) the local port forwarding rule takes care of the rest!

notice you can ping the dokku host using ping dokku.dokku.me or ping dokku.me.

virtualbox dokku machine configured a new host NAT network with IP 10.0.0.1/24. dokku.dokku.me host IP is 10.0.0.2 along with all subdomains (i.e. yourapp.dokku.me). Verify by ping dokku.me from the host.

more details https://github.com/dokku/dokku/blob/master/docs/getting-started/install/vagrant.md

app deployment (heroku/dokku/etc.) PaaS

now that dokku is up and running, we shall create the application and configure it. The steps should be generally similar if using heroku.

# create the app
dokku apps:create mavencrm

# clear any assigned domains
dokku domains:clear mavencrm

# enable vhosts support
dokku domains:add mavencrm dokku.me
dokku domains:enable mavencrm
dokku domains:clear mavencrm
# verify vhost
dokku domains:report mavencrm
  1. create the mysql service and link it
# on 0.19.x+
sudo dokku plugin:install https://github.com/dokku/dokku-mysql.git mysql
dokku mysql:create mavencrm-db
# link mysql service
dokku mysql:link mavencrm-db mavencrm

# dev-only use apt-packages plugin to inject xdebug into the environment
# on dokku 0.18.x+
sudo dokku plugin:install https://github.com/dokku-community/dokku-apt apt
# apt-packages file on the root `web` directory include `php-xdebug` which will be injected on deploy.
  1. specify os stack to use ubuntu 20 base os instead of the default Ubuntu 18 base OS
dokku buildpacks:set-property mavencrm stack gliderlabs/herokuish:latest-20

buildpacks required are detected automatically, however, this is a multi-buildpack setup. File named .buildpacks exist on the root directory which is used to let heroku/dokku know which buildpacks to use.

  1. deploy the app
# from your local machine mavencrm folder
# the remote username *must* be dokku or pushes will fail
cd mavencrm
git remote add dokku-remote [email protected]:mavencrm
# push to the remote branch called master - default branch in dokku/heroku
git push dokku-remote dev:master
-----> Cleaning up...
-----> Building mavencrm from gliderlabs/herokuish:latest-20
-----> Setting config vars
       CURL_CONNECT_TIMEOUT:  90
-----> Setting config vars
       CURL_TIMEOUT:  600
-----> Adding BUILD_ENV to build environment...
-----> PHP app detected
remote: -----> Bootstrapping...
remote: -----> Installing platform packages...
remote:        - php (7.4.22)

mounting source code files

we going to mount the local source directory to a mountpoint in the dokku box. This solution will later enable us to create a nice multi container solution.

default Vagrantfile of dokku require the following changes:

# disable out of box /vagrant mountpoint
# `vagrant halt` then we create a mount point owned by `vagrant` user by editing Vagrantfile and add
config.vm.synced_folder ".", "/vagrant", disabled: true
# herokouish buildpacks are used for the app therefore the uid and gid
config.vm.synced_folder "/path/to/source/files/mavencrm", "/mavencrm", mount_options: ["uid=32767", "gid=32767"]
#add postfix to apt-get install command to enable cron email 
postfix
#then
vagrant up

then we can do

dokku storage:mount mavencrm /var/lib/dokku/data/storage/mavencrm/web:/app/web
#restart the app
dokku ps:restart mavencrm

copying shared source code directories to VPS

#install rclone & configure using rclone config
#use rclone copy
rclone copy remote:yoursourcecodefiles/mavencrm/web web --transfers 32 --progress --fast-list  --ignore-times --no-check-dest --no-check-certificate 
# gid & uid must be 32767:32767 - as mounted to herokuish will require ids to match /app/ 
cd /var/lib/dokku/data/storage && sudo mv ~/mavencrm mavencrm && sudo chown -R 32767:32767 mavencrm
# now we can either manually mount or use require plugin which will mount automatically based on `volumes` key in `app.json`


cron setup

dokku app.json entry to create a cron schedule looks like the below

  "cron": [
    {
      "command": "$SHELL web/cron/RunCron.sh >/dev/null 2>&1",
      "schedule": "*/5 * * * *"
    }
  ],

note: cron is now setup using sleep. this ensures that cron runs in its dedicated container. executable is RunSleep.sh defined in Procfile install postfix in Vagrantfile apt-get install in order for cron to send mail notification of errors otherwise you would get “(CRON) info (No MTA installed, discarding output)” error from the syslog. grep CRON /var/log/syslog to see the log for troubleshooting.

cat /var/mail/root to view the mail received from cron - stating errors if a cronjob fails to work

storage using rclone

rclone copy remote:path folder --transfers 32 --progress --fast-list  --ignore-times --no-check-dest --no-check-certificate

app.json