Dokku: deploy, build & serve middleman statically generated website - ruby

Today, I've been trying to configure Dokku to deploy a statically-generated website of mine (built with middleman): push the middleman source to the host, generate the website on the host, and tell a nginx to serve those static files.
Following these resources 1 and 2, I setup my project with:
a .buildpacks file, containing one buildpack to build the site, and the nginx buildpack to serve the generated static HTML files:
https://github.com/heroku/heroku-buildpack-ruby.git#v222
https://github.com/dokku/buildpack-nginx.git#v14
a .static file so that the nginx buildpack knows it must serve a static website
a predeploy action in charge of building the site, using app.json :
{
"scripts": {
"dokku": {
"predeploy": "bundle exec middleman build",
}
}
}
What happened?
Apparently, at the moment I'm trying to build my middleman site with the predeploy hook, the bundle command is not available anymore. Here's an example output I'm getting:
➜ git push dokku master
Enumerating objects: 397, done.
Counting objects: 100% (397/397), done.
Delta compression using up to 8 threads
Compressing objects: 100% (258/258), done.
Writing objects: 100% (397/397), 819.50 KiB | 14.90 MiB/s, done.
Total 397 (delta 195), reused 244 (delta 111), pack-reused 0
remote: Resolving deltas: 100% (195/195), done.
-----> Cleaning up...
-----> Building site from herokuish...
-----> Adding BUILD_ENV to build environment...
-----> Warning: Multiple default buildpacks reported the ability to handle this app. The first buildpack in the list below will be used.
Detected buildpacks: multi ruby static
-----> Multipack app detected
=====> Downloading Buildpack: https://github.com/heroku/heroku-buildpack-ruby.git
=====> Detected Framework: Ruby
-----> Installing bundler 2.1.4
-----> Removing BUNDLED WITH version in the Gemfile.lock
-----> Compiling Ruby/Rack
-----> Using Ruby version: ruby-2.6.3
-----> Installing dependencies using bundler 2.1.4
Running: BUNDLE_WITHOUT='development:test' BUNDLE_PATH=vendor/bundle BUNDLE_BIN=vendor/bundle/bin BUNDLE_DEPLOYMENT=1 bundle install -j4
Using concurrent-ruby 1.1.7
Using i18n 0.9.5
Using minitest 5.14.2
Using thread_safe 0.3.6
Using tzinfo 1.2.7
Using activesupport 5.2.4.4
Using public_suffix 4.0.6
Using addressable 2.7.0
Using execjs 2.7.0
Using autoprefixer-rails 9.8.6.5
Using backports 3.18.2
Using bundler 2.1.4
Using coffee-script-source 1.12.2
Using coffee-script 2.4.1
Using contracts 0.13.0
Using dotenv 2.7.6
Using erubis 2.7.0
Using fast_blank 1.0.0
Using fastimage 2.2.0
Using ffi 1.13.1
Using temple 0.8.2
Using tilt 2.0.10
Using haml 5.2.0
Using hamster 3.0.0
Using hashie 3.6.0
Using rexml 3.2.4
Using kramdown 2.3.0
Using rb-fsevent 0.10.4
Using rb-inotify 0.10.1
Using listen 3.0.8
Using memoist 0.16.2
Using thor 1.0.1
Using middleman-cli 4.3.11
Using padrino-support 0.13.3.4
Using padrino-helpers 0.13.3.4
Using parallel 1.19.2
Using rack 2.2.3
Using sassc 2.4.0
Using servolux 0.13.0
Using uglifier 3.2.0
Using middleman-core 4.3.11
Using middleman 4.3.11
Using middleman-autoprefixer 2.10.1
Bundle complete! 3 Gemfile dependencies, 43 gems now installed.
Gems in the groups development and test were not installed.
Bundled gems are installed into `./vendor/bundle`
Bundle completed (0.52s)
Cleaning up the bundler cache.
-----> Writing config/database.yml to read from DATABASE_URL
-----> Installing node-v12.16.2-linux-x64
-----> Detecting rake tasks
###### WARNING:
No Procfile detected, using the default web server.
We recommend explicitly declaring how to boot your server process via a Procfile.
https://devcenter.heroku.com/articles/ruby-default-web-server
=====> Downloading Buildpack: https://github.com/dokku/buildpack-nginx.git
=====> Detected Framework: .static
-----> Copy static files to www
-----> Reusing nginx binary from cache
-----> Using default app-nginx.conf.sigil
-----> Using default mime.types
Using release configuration from last framework (.static).
-----> Discovering process types
Default types for -> web
-----> Releasing site...
-----> Deploying site...
-----> Checking for predeploy task
-----> Executing predeploy task from app.json: bundle exec middleman build
=====> Start of site predeploy task (22fcf68dd) output
remote: ! Execution of predeploy task failed: bundle exec middleman build
/bin/bash: bundle: command not found
remote: 2021/01/02 15:06:19 exit status 1
remote: 2021/01/02 15:06:19 exit status 1
remote: 2021/01/02 15:06:19 exit status 1
=====> End of site predeploy task (22fcf68dd) output
To host:site
! [remote rejected] master -> master (pre-receive hook declined)
error: failed to push some refs to 'host:site'
What I tried
I noticed the first buildpack is executed, then the second one, then the predeploy hook kicks in.
I tried removing the nginx "static serve" buildpack and keep only the ruby one, and keep a bundle command in my predeploy hook. It worked and I didn't get the "command not found" error. So switching to the second buildpack seems to be messing things up for me.
I compared the path with and without the nginx "static serve" buildpack, and nothing weird. With the nginx buildpack, a new path is added but the previously set ruby paths are still there:
# with only ruby buildpack
/app/bin:/app/vendor/bundle/bin:/app/vendor/bundle/ruby/2.6.0/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
# with both ruby & nginx buildpacks
/app/bin:/app/vendor/bundle/bin:/app/vendor/bundle/ruby/2.6.0/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/app/nginx
Eventually, I'm a bit lost here. Is it expected? Am I not following the dokku way? Am I getting this because of permissions issues, or something in Dokku that I'm not aware of?
For now, as a fallback, I'm serving the site by running a middleman server that receives all requests, but it makes no sense to dynamically serve a statically-generated website.

Thanks to jonrsharpe comment, I reoriented my searches and found this blog post on heroku engineering blog. Eventually, as stated by jonrsharpe:
The Nginx buildpack won't have Ruby in at all - you need to do any building in the Ruby buildpack context, so all the static buildpack needs to do is serve the results.
Therefore, to launch my middleman build command, I needed to hook somewhere in the ruby buildpack thing. And in the "jekyll on heroku" link, everything is explained: one should override the assets:precompile rake task.
Steps I followed
Add gem "rake" to my Gemfile (and bundle, of course)
Create a Rakefile with the assets:precompile task :
task "assets:precompile" do
exec("middleman build")
end
Enjoy!

Related

Minimal `Gemfile/Gemfile.lock` for Heroku environment

I’m updating the environment on Heroku and one of the buildpack we use is based on Ruby, which is no longer available by default in the new heroku-22 environment/stack (nor required by our PHP app).
From the docs:
[...] end users should add the Ruby buildpack prior to the buildpack in question (they will also need to ensure minimal Gemfile / Gemfile.lock files exist, so that the Ruby buildpack passes detection).
However I have no clue what those files should include as I have zero experience with Ruby. What would be a valid set of minimal Gemfiles to trigger Ruby installation on Heroku?
I suggest you don't use that buildpack at all. It's ancient, and third-party buildpacks are always a bit questionable, even if it's just because they often stop getting updated.
Here's what it claims to do:
This is a Heroku buildpack for vendoring just the mysql binary from the mysql-client-core deb package.
If you just need a mysql binary, you can use the apt buildpack to install it without worrying about Ruby or anything like that.
Add it as your first buildpack:
heroku buildpacks:add --index 1 heroku-community/apt
Create an Aptfile in the root directory of your project that lists the Ubuntu packages you wish to install, e.g.
mysql-client-core-8.0
Note that the buildpack does not do dependency resolution. If any packages you list have their own dependencies you may have to list them explicitly.
Commit, and redeploy.
You should see the Ubuntu packages you listed get installed before your main buildpack runs.
In any case, if you really want to make your application compatible with the Ruby buildpack you should be able to simply include an empty Gemfile in the root of your project:
The Heroku Ruby Support will be applied to applications only when the application has a Gemfile in the root directory. Even if an application has no gem dependencies it should include an empty Gemfile to document that your app has no gem dependencies.
A Gemfile.lock is not required.
Note that you'll need to manually add the buildpacks you require. I believe you'll want Ruby first, then the MySQL buildpack in your question, then whatever language your application is written in, which appears to be PHP:
heroku buildpacks:set heroku/php # Main buildpack; we insert others before it below
heroku buildpacks:add --index 1 heroku/ruby
heroku buildpacks:add --index 2 https://github.com/thoughtbot/heroku-buildpack-mysql.git
heroku buildpacks
# => Should print the buildpacks in the expected order
Edited
It turns out an empty Gemfile is not enough and a Gemfile.lock is actually required as well.
-----> Building on the Heroku-22 stack
-----> Using buildpacks:
1. heroku/python
2. heroku/ruby
3. https://github.com/thoughtbot/heroku-buildpack-mysql
4. heroku/php
5. heroku/nodejs
-----> Python app detected
-----> Using Python version specified in runtime.txt
-----> Stack has changed from heroku-20 to heroku-22, clearing cache
-----> No change in requirements detected, installing from cache
-----> Installing python-3.10.8
-----> Installing pip 22.2.2, setuptools 63.4.3 and wheel 0.37.1
-----> Installing SQLite3
-----> Installing requirements with pip
Collecting supervisor
Downloading supervisor-4.2.4-py2.py3-none-any.whl (749 kB)
Installing collected packages: supervisor
Successfully installed supervisor-4.2.4
-----> Ruby app detected
grep: /tmp/build_bebc9aa2/Gemfile.lock: No such file or directory
-----> Compiling Ruby/NoLockfile
!
! Gemfile.lock required. Please check it in.
!
! Push rejected, failed to compile Ruby app.
! Push failed
An empty Gemfile will trigger the Ruby installation, however the heroku/ruby package itself does require a lock file.
The buildpack will detect your app as Ruby if it has a Gemfile and Gemfile.lock files in the root directory.
After some trial and error I figure out the following files work:
# Gemfile
source 'https://rubygems.org'
# Gemfile.lock
GEM
remote: https://rubygems.org/
specs:
PLATFORMS
ruby
DEPENDENCIES
BUNDLED WITH
1.17.3

Deploying a sinatra app produced on a mac to Heroku

I have built a simple sinatra web app on my macbook. The deployment to heroku fails with the logs below. The problem is that I've already implemented their suggested fix (bundle lock --add-platform x86_64-linux) and I still get the same error message.
Any suggestions as to next steps would be very welcome. Thanks in advance.
-----> Building on the Heroku-20 stack
-----> Determining which buildpack to use for this app
-----> Ruby app detected
-----> Installing bundler 2.2.33
-----> Removing BUNDLED WITH version in the Gemfile.lock
-----> Compiling Ruby/Rack
-----> Using Ruby version: ruby-2.7.5
-----> Installing dependencies using bundler 2.2.33
Running: BUNDLE_WITHOUT='development:test' BUNDLE_PATH=vendor/bundle BUNDLE_BIN=vendor/bundle/bin BUNDLE_DEPLOYMENT=1 bundle install -j4
Your bundle only supports platforms ["arm64-darwin-20"] but your local platform
is x86_64-linux. Add the current platform to the lockfile with `bundle lock
--add-platform x86_64-linux` and try again.
Bundler Output: Your bundle only supports platforms ["arm64-darwin-20"] but your local platform
is x86_64-linux. Add the current platform to the lockfile with `bundle lock
--add-platform x86_64-linux` and try again.
!
! Failed to install gems via Bundler.
!
! Push rejected, failed to compile Ruby app.
! Push failed
*Update
My local repo, with x86_64-linux in Gemfile.lock, is out of sync with the remote repo on github that I have been trying to deploy from. Other files are out of date too. Concerningly, I have both pushed and pulled recently, as well as deleted the remote repo, created a new one and pushed again. Git is telling me that both the local and the remote repos are up to date with each other, when they are obviously not.
I've tried pushing directly to heroku from the command line but hit the same platform error as above.

Heroku rejecting my app all of a sudden (env: bundle: No such file or directory)

I tried deploying my application today and my deployments are for the first time being rejected.
My deployment output is below. I've tried the following with no change in outcome:
Deploying with no Ruby version in Gemfile
Deploying with 2.1.0 in Gemfile
Deploying using a custom BUILDPACK_URL at https://github.com/heroku/heroku-buildpack-ruby.git
Deploying from a different branch
Deploying from a teammate's machine
Rolling back to last successfully deployed commit, changing a line in the README, committed and redeployed.
I had successfully deployed just last night. I only have made HTML and CSS changes to the new code I want to commit, so nothing in the app settings has been changed since the last successful deployment.
Why would Heroku be now rejecting my app deployments?
Thanks!
Fetching repository, done.
Counting objects: 11, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (6/6), done.
Writing objects: 100% (6/6), 496 bytes, done.
Total 6 (delta 5), reused 0 (delta 0)
-----> Ruby app detected
-----> Compiling Ruby/Rails
-----> Using Ruby version: ruby-2.0.0
-----> Installing dependencies using 1.5.2
Running: bundle install --without development:test --path vendor/bundle --binstubs vendor/bundle/bin -j4 --deployment
env: bundle: No such file or directory
Bundler Output: env: bundle: No such file or directory
!
! Failed to install gems via Bundler.
!
! Push rejected, failed to compile Ruby app
To git#heroku.com:myapp.git
! [remote rejected] development -> master (pre-receive hook declined)
error: failed to push some refs to 'git#heroku.com:myapp.git'
Heroku dropped support for Rails 1.9 and that was in the PATH. I had some trouble dropping the PATH because heroku had some hack where it was configured, but would not drop (probably because it was a default).
So I ended up setting the PATH to something
heroku config:set PATH=blah
and then unsetting it.
heroku config:remove PATH
That seems to have stuck.

Using ruby and graphviz on heroku with heroku-buildpack-multi

I'm trying to deploy my app on heroku. I use declarative_authorization with graphical visualisation.
I installed https://github.com/ddollar/heroku-buildpack-multi heroku config:set BUILDPACK_URL=https://github.com/ddollar/heroku-buildpack-multi and created .buildpacks with:
https://github.com/stigkj/heroku-buildpack-graphviz.git
https://github.com/heroku/heroku-buildpack-ruby.git
Building works fine:
-----> Fetching custom git buildpack... done
-----> Multipack app detected
=====> Downloading Buildpack: https://github.com/stigkj/heroku-buildpack-graphviz.git
=====> Detected Framework: graphviz
-----> Fetching and installing graphviz
grapvhiz installed
=====> Downloading Buildpack: https://github.com/heroku/heroku-buildpack-ruby.git
=====> Detected Framework: Ruby/Rails
-----> Using Ruby version: ruby-1.9.3
But now I get when I access the graph:
Errno::ENOENT in AuthorizationRulesController#graph
No such file or directory - dot -q -Tsvg
What is the correct path?
Use https://github.com/gokceneraslan/heroku-buildpack-graphviz instead of https://github.com/stigkj/heroku-buildpack-graphviz.git.
Then, add this configuration:
heroku config:add PATH:/usr/local/bin:/usr/bin:/bin:/app/bin
Source: https://github.com/pygram/pygram#deployment-on-heroku
https://github.com/weibeld/heroku-buildpack-graphviz is a stable buildpack for Graphviz (see instructions there).
It automatically adds the location of dot and other Graphviz executables to the PATH.

No Cedar supported app detected error in Sinatra Heroku app

Seems like everything worked fine when I pushed to Heroku as shown below. Then I run into an error on the latter while following Heroku's Docs: http://devcenter.heroku.com/articles/ruby#install_the_heroku_commandline_client
-----> Heroku receiving push
-----> Removing .DS_Store files
-----> Ruby app detected
-----> Installing dependencies using Bundler version 1.1.rc.7
Running: bundle install --without development:test --path vendor/bundle --binstubs bin/ --deployment
Fetching gem metadata from http://rubygems.org/.....
Installing rack (1.4.0)
Installing tilt (1.3.3)
Installing sinatra (1.1.0)
Using bundler (1.1.rc.7)
Your bundle is complete! It was installed into ./vendor/bundle
Cleaning up the bundler cache.
-----> Discovering process types
Procfile declares types -> (none)
Default types for Ruby -> console, rake
-----> Compiled slug size is 16.3MB
-----> Launching... done, v4
http://cold-mountain-8923.herokuapp.com deployed to Heroku
With heroku.logs I get:
2012-01-11T06:36:43+00:00 heroku[slugc]: Slug compilation started
2012-01-11T06:36:43+00:00 heroku[slugc]: Slug compilation failed: no Cedar-supported app detected
2012-01-11T06:47:20+00:00 heroku[slugc]: Slug compilation started
2012-01-11T06:47:22+00:00 heroku[slugc]: Slug compilation failed: failed to compile Ruby app
2012-01-11T06:52:21+00:00 heroku[slugc]: Slug compilation started
How is there no Cedar-support detected when the Gemfile and Procfile are both in there?
Also, nothing appears on the heroku webpage.
Works fine for me--double check your Procfile is up to date on Heroku. Here's the output of my push:
Counting objects: 46, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (28/28), done.
Writing objects: 100% (46/46), 15.23 MiB | 774 KiB/s, done.
Total 46 (delta 11), reused 46 (delta 11)
-----> Heroku receiving push
-----> Removing .DS_Store files
-----> Ruby/Rack app detected
-----> Installing dependencies using Bundler version 1.1.rc.7
Running: bundle install --without development:test --path vendor/bundle --binstubs bin/ --deployment
Fetching gem metadata from http://rubygems.org/.....
Installing rack (1.4.0)
Installing rack-protection (1.2.0)
Installing tilt (1.3.3)
Installing sinatra (1.3.2)
Using bundler (1.1.rc.7)
Your bundle is complete! It was installed into ./vendor/bundle
Cleaning up the bundler cache.
-----> Discovering process types
Procfile declares types -> web
Default types for Ruby/Rack -> console, rake
-----> Compiled slug size is 16.5MB
-----> Launching... done, v4
http://growing-dawn-4276.herokuapp.com deployed to Heroku
To git#heroku.com:growing-dawn-4276.git
* [new branch] master -> master
I cloned my app on Github, deleted my original Heroku app, and created a new one. Now I have it running! My conclusion is that the original Heroku app was created before I made all the new changes, and commits just weren't getting updated or pushed properly somehow. By creating a new app, I don't lose a thing since the code is the same, and Heroku allows for abundant app creations. I suspect this had something to do with git remote issues that I had not taken account for.

Resources