foodsoft on docker using the official image

Oh boy, this is a hard setup. Sorry.

I am following https://github.com/foodcoops/foodsoft/blob/master/doc/SETUP_PRODUCTION.md
using the official production docker image. I have mysql DB running and redis on localhost

According to that, I need to prepare an app_config.yml, and place it in pwd/config/app_config.yml. Check.
I need to set the env vars:
DATABASE_URL=mysql2://foodsoft:xxxxx@192.168.178.52:3306/foodsoftdb?encoding=utf8
REDIS_URL=redis://192.168.178.52:6379
SECRET_KEY_BASE=ZpIw6tz6AT8rVuTQxM1sIfh2vLoTx9
Check.

Then this fails:
$ docker run --name foodsoft_web --rm -e SECRET_KEY_BASE -e DATABASE_URL -e REDI
S_URL -e RAILS_FORCE_SSL=false -v pwd/config/app_config.yml:/usr/src/app/con
fig/app_config.yml:ro foodcoops/foodsoft bundle exec rake db:setup

Here is the trace:
/nonexistent is not a directory.
Bundler will use /tmp/bundler/home/unknown' as your home directory temporarily. foodsoftdb already exists Loading app configuration from config/app_config.yml rake aborted! Errno::EISDIR: Is a directory @ io_fread - /usr/src/app/config/app_config.yml /usr/src/app/lib/foodsoft_config.rb:63:in read’
/usr/src/app/lib/foodsoft_config.rb:63:in init' /usr/src/app/config/initializers/01_load_app_config.rb:5:in <top (required)>’
[…]

I am supposed to create a directory /nonexistent?
The DB already exists, correct. I created it manually.
/usr/src/app/config/app_config.yml is NOT a dir, I run with bash as entrypoint and verifiied:
docker run -it --entrypoint /bin/bash foodcoops/foodsoft
nobody@830959cd5b59:/usr/src/app$ ls -l config
total 68
-rwxr-xr-x 1 root root 5831 Jan 7 16:54 app_config.yml
[…]

I also tried with a Windows path, and with the complete config directory bound from host
$ docker run --name foodsoft_web --net=host --rm -e SECRET_KEY_BASE -e DATABASE_URL -e REDIS_URL -e RAILS_FORCE_SSL=false -v d:\sprev\Source\Repos\foodsoft\config:/usr/src/app/config:ro foodcoops/foodsoft bundle exec rake db:setup
/nonexistent is not a directory.
Bundler will use /tmp/bundler/home/unknown' as your home directory temporarily.rake aborted! LoadError: cannot load such file -- /usr/src/app/config/application /usr/src/app/Rakefile:4:in require’
[…]

Hi,

Thanks for sharing your experience. Sorry it’s been a hard ride until now! Let’s see.

The issue you’re having here is that the app configuration cannot be found. Weirdly enough, the config file is mounted as a directory (instead of a file). In my local test with this, that didn’t happen. Could it be related to a different Docker version and/or platform (Windows)? In any case, you could also build a derived Docker image with the configuration inside, like this example, run docker build and start the resulting image.

If you mount the complete directory, you need all the files in there (and not just app_config.yml). The error you’re seeing when supplying a directory, is caused by these missing files.

Hope this helps a little. Please let us know how it goes.

Best,

  • Willem

p.s. Be careful sharing SECRET_KEY_BASE, of course.

Hello,

we are members of a food cooperative trying to install foodsoft on our dedicated Debian server. Docker seems like the easiest way, but it’s quite hard to find accurate information about how to configure the app.
After a lot of hours of unsuccesful trying and searching, we come here to find help.

We installed docker, ran docker pull, installed rvm, ruby on rails and redis. Now we are stuck at the configuration step :

  • we can’t find the application’s root directory to put the app_config.yml fils inside. The command Rails.root returns “command not found”

  • the command rake secret returns “no rakefile found” Where to crreat the rakefile and what to put inside ?

  • can the config function with an external mysql instance (meaning not inside docker, but as a debian package)

  • will we be able to access the docker/foodosft instance with classic HTTP request ?

After having succeeded we can create a detailed deployment tuto for unskilled users like us.

Hi Noid,

Thanks your mail! I’m sorry to hear it wasn’t so easy to get started with a production setup using Docker. But you’re at the right place to ask for help (foodsoft-discuss would also be a good place).

This is Just a quick reply to check: did you consider reading ? As far as I understand, it explains what you’d like to do to get started. It doesn’t explain how to start Redis and MySQL/MariaDB, though, but these should be relatively ‘standard’ to setup.

Kind regards,

  • Willem

Hi, thank you for your quick answer.

Actually we (of course) have read and dissected the page you mention for several hours before posting. We also have googled every single question we asked on this topic, and compared our minds about it. We also tryed some docker tutos, and even installed other apps to check our knowledge.
Redis and mysql don’t seem to be an obstacle, as we already know about creating new databases and all that stuff.

The problem is finding the directories paths :

  • where to put the rakefile to have “rake secret” output a key ? The command outputs “no rakefile found”. Eventually what to put inside the rakefile would help us.

  • where to put app_config.yml ? (where is the ‘pwd’/config mentioned above ?)

Great :slight_smile:
Now I see parts of the doc were written assuming you already have Foodsoft running locally. That, of course, is a strange assumption.
So you can just make your own 30-char random string instead of ‘rake secret’, or run the command inside the container.
The app config you can download from https://github.com/foodcoops/foodsoft/blob/master/config/app_config.yml.SAMPLE and use the downloaded and adapted file path as the first part after -v.

Hope this helps a bit!

Cheers,

  • Willem

Ok thank you, this gives some useful details.

Now I’m trying to explore the containers filesystem to find the config directory where to put the app_config.yml.

~# docker container ls -a
CONTAINER ID        IMAGE                COMMAND                  CREATED             STATUS                   PORTS               NAMES
6beecd78476c        hello-world          "/hello"                 2 weeks ago         Exited (0) 2 weeks ago                       hungry_saha
fbc727be9b42        hello-world          "/hello"                 3 weeks ago         Exited (0) 3 weeks ago                       laughing_agnesi
1c3c62a1cbfc        foodcoops/foodsoft   "./docker-entrypoint…"   3 weeks ago         Up 3 seconds             3000/tcp            mystifying_heisenberg

~# docker exec -it 1c3c62a1cbfc bash
Error response from daemon: Container 1c3c62a1cbfc8dcdc2f22037c8f0aa82129fd00eae3a46a62caaedb0a573ee6d is not running

I started the container with

docker container start 1c3c62a1cbfc 

would this mean I should run it instead ? But I can’t run it without the .yml file right ? I’m quite lost here…

By the more I don’t understant the end of this sentence :

Great, it seems like you’re slowly getting somewhere.

Now what you need is some more understanding of how docker containers
work, and how to use volumes.

Firstly, you cannot change many things about a docker container that was
already started: environment, volumes, used image, they are all fixed
(see, for example this SO question
https://stackoverflow.com/questions/27812548/how-to-set-an-environment-variable-in-a-running-docker-container
about the environment), not even when you’ve stopped it and start it
again. Normally, you’d just create a new container with the new options.

Secondly, you’ll need to understand a bit how volumes work (see docker
run’s manpage
https://docs.docker.com/engine/reference/run/#volume-shared-filesystems).
Docker run uses the -v parameter for this, with an argument in three
parts: -v host-src:container-dest:options. While often volumes are used
on directories, here we use it on just a single file: app_config.yml.
The Foodsoft Docker container expects it in
/usr/src/app/config/app_config.yml. Now if you download the
configuration file
https://github.com/foodcoops/foodcoops.net/blob/master/foodsoft/app_config.yml
to e.g. /var/local/foodsoft/app_config.yml, you could use the following
with docker run: -v
/var/local/foodsoft/app_config.yml:/usr/src/app/config/app_config.yml:ro

Does that bring you any further?

Kind regards,

  • Willem

Thank you this is exactly what I needed !

Now I wonder where I should define the environment variables if not in the run command itself ?

I see on different manuals that there are various ways to declare those variables, I guess the one you chose in your tuto is an env file, but I don’t know where docker expects it to be placed.

For regular docker (as you use), that would be the normal environment.
So you’d just set an environment variable in the shell, expose it with
the -e argument, then the environment will also be available in the
docker container. Or pass key and value on the command line. RTFM:
https://docs.docker.com/engine/reference/run/#env-environment-variables
https://docs.docker.com/engine/reference/commandline/run/#set-environment-variables--e---env---env-file

(When using docker-compose, you can put it in the docker-compose
configuration file, and set private variables in a separate env-file -
https://docs.docker.com/compose/environment-variables/
But that’s not something you need to worry about now - I’d first get it
running with plain docker, not using docker-compose, as that’s the path
you’re getting along nicely now, as it looks like.)

The .env file in the Foodsoft repository is for development purposes, it
is not used on production nor in the Docker container (but I could be
wrong).

Hello !

I finally found some hours to try this new tip you gave me. Looks like I’m getting closer !

Here is what I ran :

docker run --name foodsoft_web -p 3000 \
  -e SECRET_KEY_BASE='mYunBreAkaBleKEY15476147654145' -e DATABASE_URL='mysql:latest//root:foodsoft@my.host:3306/foodsoftdb?encoding=utf8' -e REDIS_URL='redis://my.host:6379' -e RAILS_FORCE_SSL=false \
  -v /var/www/app_config.yml:/usr/src/app/config/app_config.yml:ro \
  foodcoops/foodsoft

This spits out a lot of text, but my instance is not up :

Here is the output of ‘docker run’ command

/nonexistent is not a directory.
Bundler will use /tmp/bundler/home/unknown' as your home directory temporarily. => Booting Thin => Rails 4.2.10 application starting in production on http://0.0.0.0:3000 => Run rails server -hfor more startup options => Ctrl-C to shutdown server Exiting /usr/src/app/vendor/bundle/ruby/2.3.0/gems/activerecord-4.2.10/lib/active_record/connection_adapters/connection_specification.rb:177:inrescue in spec’: Specified ‘mysql’ for database adapter, but the gem is not loaded. Add gem 'mysql' to your Gemfile (and ensure its version is at the minimum required by ActiveRecord). (Gem::LoadError)
from /usr/src/app/vendor/bundle/ruby/2.3.0/gems/activerecord-4.2.10/lib/active_record/connection_adapters/connection_specification.rb:174:in spec' from /usr/src/app/vendor/bundle/ruby/2.3.0/gems/activerecord-4.2.10/lib/active_record/connection_handling.rb:50:in establish_connection’
from /usr/src/app/vendor/bundle/ruby/2.3.0/gems/activerecord-4.2.10/lib/active_record/railtie.rb:122:in block (2 levels) in <class:Railtie>' from /usr/src/app/vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.10/lib/active_support/lazy_load_hooks.rb:38:in instance_eval’
from /usr/src/app/vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.10/lib/active_support/lazy_load_hooks.rb:38:in execute_hook' from /usr/src/app/vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.10/lib/active_support/lazy_load_hooks.rb:28:in block in on_load’
from /usr/src/app/vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.10/lib/active_support/lazy_load_hooks.rb:27:in each' from /usr/src/app/vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.10/lib/active_support/lazy_load_hooks.rb:27:in on_load’
from /usr/src/app/vendor/bundle/ruby/2.3.0/gems/activerecord-4.2.10/lib/active_record/railtie.rb:118:in block in <class:Railtie>' from /usr/src/app/vendor/bundle/ruby/2.3.0/gems/railties-4.2.10/lib/rails/initializable.rb:30:in instance_exec’
from /usr/src/app/vendor/bundle/ruby/2.3.0/gems/railties-4.2.10/lib/rails/initializable.rb:30:in run' from /usr/src/app/vendor/bundle/ruby/2.3.0/gems/railties-4.2.10/lib/rails/initializable.rb:55:in block in run_initializers’
from /usr/local/lib/ruby/2.3.0/tsort.rb:228:in block in tsort_each' from /usr/local/lib/ruby/2.3.0/tsort.rb:350:in block (2 levels) in each_strongly_connected_component’
from /usr/local/lib/ruby/2.3.0/tsort.rb:431:in each_strongly_connected_component_from' from /usr/local/lib/ruby/2.3.0/tsort.rb:349:in block in each_strongly_connected_component’
from /usr/local/lib/ruby/2.3.0/tsort.rb:347:in each' from /usr/local/lib/ruby/2.3.0/tsort.rb:347:in call’
from /usr/local/lib/ruby/2.3.0/tsort.rb:347:in each_strongly_connected_component' from /usr/local/lib/ruby/2.3.0/tsort.rb:226:in tsort_each’
from /usr/local/lib/ruby/2.3.0/tsort.rb:205:in tsort_each' from /usr/src/app/vendor/bundle/ruby/2.3.0/gems/railties-4.2.10/lib/rails/initializable.rb:54:in run_initializers’
from /usr/src/app/vendor/bundle/ruby/2.3.0/gems/railties-4.2.10/lib/rails/application.rb:352:in initialize!' from /usr/src/app/vendor/bundle/ruby/2.3.0/gems/railties-4.2.10/lib/rails/railtie.rb:194:in public_send’
from /usr/src/app/vendor/bundle/ruby/2.3.0/gems/railties-4.2.10/lib/rails/railtie.rb:194:in method_missing' from /usr/src/app/config/environment.rb:5:in <top (required)>’
from /usr/src/app/vendor/bundle/ruby/2.3.0/gems/polyglot-0.3.5/lib/polyglot.rb:65:in require' from /usr/src/app/vendor/bundle/ruby/2.3.0/gems/polyglot-0.3.5/lib/polyglot.rb:65:in require’
from /usr/src/app/vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.10/lib/active_support/dependencies.rb:274:in block in require' from /usr/src/app/vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.10/lib/active_support/dependencies.rb:240:in load_dependency’
from /usr/src/app/vendor/bundle/ruby/2.3.0/gems/activesupport-4.2.10/lib/active_support/dependencies.rb:274:in require' from /usr/src/app/config.ru:3:in block in ’
from /usr/src/app/vendor/bundle/ruby/2.3.0/gems/rack-1.6.10/lib/rack/builder.rb:55:in instance_eval' from /usr/src/app/vendor/bundle/ruby/2.3.0/gems/rack-1.6.10/lib/rack/builder.rb:55:in initialize’
from /usr/src/app/config.ru:in new' from /usr/src/app/config.ru:in
from /usr/src/app/vendor/bundle/ruby/2.3.0/gems/rack-1.6.10/lib/rack/builder.rb:49:in eval' from /usr/src/app/vendor/bundle/ruby/2.3.0/gems/rack-1.6.10/lib/rack/builder.rb:49:in new_from_string’
from /usr/src/app/vendor/bundle/ruby/2.3.0/gems/rack-1.6.10/lib/rack/builder.rb:40:in parse_file' from /usr/src/app/vendor/bundle/ruby/2.3.0/gems/rack-1.6.10/lib/rack/server.rb:300:in build_app_and_options_from_config’
from /usr/src/app/vendor/bundle/ruby/2.3.0/gems/rack-1.6.10/lib/rack/server.rb:209:in app' from /usr/src/app/vendor/bundle/ruby/2.3.0/gems/railties-4.2.10/lib/rails/commands/server.rb:61:in app’
from /usr/src/app/vendor/bundle/ruby/2.3.0/gems/rack-1.6.10/lib/rack/server.rb:337:in wrapped_app' from /usr/src/app/vendor/bundle/ruby/2.3.0/gems/rack-1.6.10/lib/rack/server.rb:273:in start’
from /usr/src/app/vendor/bundle/ruby/2.3.0/gems/railties-4.2.10/lib/rails/commands/server.rb:80:in start' from /usr/src/app/vendor/bundle/ruby/2.3.0/gems/railties-4.2.10/lib/rails/commands/commands_tasks.rb:80:in block in server’
from /usr/src/app/vendor/bundle/ruby/2.3.0/gems/railties-4.2.10/lib/rails/commands/commands_tasks.rb:75:in tap' from /usr/src/app/vendor/bundle/ruby/2.3.0/gems/railties-4.2.10/lib/rails/commands/commands_tasks.rb:75:in server’
from /usr/src/app/vendor/bundle/ruby/2.3.0/gems/railties-4.2.10/lib/rails/commands/commands_tasks.rb:39:in run_command!' from /usr/src/app/vendor/bundle/ruby/2.3.0/gems/railties-4.2.10/lib/rails/commands.rb:17:in <top (required)>’
from bin/rails:4:in require' from bin/rails:4:in
[/quote]

I checked Rails and Ruby version as follows

$ rails -v
Rails 4.2.2
$ ruby -v
ruby 2.1.5p273 (2014-11-13) [x86_64-linux-gnu]
root@host:~# rvm use 2.3.0 Required ruby-2.3.0 is not installed. To install do: 'rvm install "ruby-2.3.0"'

root@host:~# rvm install “ruby-2.3.0”
Warning, new version of rvm available ‘1.29.7-next’, you are using older version ‘1.29.4’.
You can disable this warning with: echo rvm_autoupdate_flag=0 >> ~/.rvmrc
You can enable auto-update with: echo rvm_autoupdate_flag=2 >> ~/.rvmrc
Searching for binary rubies, this might take some time.
No binary rubies available for: debian/8/x86_64/ruby-2.3.0.
Continuing with compilation. Please read ‘rvm help mount’ to get more information on binary rubies.
Checking requirements for debian.
Requirements installation successful.
Installing Ruby from source to: /root/.rvm/rubies/ruby-2.3.0, this may take a while depending on your cpu(s)…
ruby-2.3.0 - #downloading ruby-2.3.0, this may take a while depending on your connection…
curl: (3) malformed
There was an error(3).

No fallback URL can be calculated for /2.3/ruby-2.3.0.tar.bz2, open a ticket with full output here:

https://github.com/rvm/rvm/issues

There has been an error fetching the ruby interpreter. Halting the installation.
[/quote]

Hi,

"mysql:latest” is not an installed database driver. Use “mysql2” instead:

Try to run it with DATABASE_URL=‘mysql2://root:foodsoft@my.host:3306/foodsoftdb?encoding=utf8’

Same issue when I try to run with ‘mysql2’ instead of ‘mysql:latest’

`/nonexistent` is not a directory.
Bundler will use `/tmp/bundler/home/unknown' as your home directory temporarily.
/usr/src/app/vendor/bundle/ruby/2.3.0/gems/activerecord-4.2.10/lib/active_record/connection_adapters/connection_specification.rb:37:in `initialize': undefined method `tr' for nil:NilClass (NoMethodError)
	from /usr/src/app/vendor/bundle/ruby/2.3.0/gems/activerecord-4.2.10/lib/active_record/connection_adapters/connection_specification.rb:270:in `new'
	from /usr/src/app/vendor/bundle/ruby/2.3.0/gems/activerecord-4.2.10/lib/active_record/connection_adapters/connection_specification.rb:270:in `resolve_url_connection'
etc....

Hi ! I really need help with this.

It looks like there is an issue with ruby version, but I can’t manage to install the latest version with rvm as stated above.

Maybe it deals with the gemfile related to mysql bt I truly don’t know where is located that “Gemfile”. Maybe I should not use a docker image of mysql ?

I saw there are different issues when I run the container with mysql:latest and with mysql2.

first issue with mysql:latest

/usr/src/app/vendor/bundle/ruby/2.3.0/gems/activerecord-4.2.10/lib/active_record/connection_adapters/connection_specification.rb:177:in `rescue in spec': Specified 'mysql' for database adapter, but the gem is not loaded. Add `gem 'mysql'` to your Gemfile (and ensure its version is at the minimum required by ActiveRecord). (Gem::LoadError)

As far I can understand, it looks like mysql is not properly linked. So the second solution should bring me a step further.

second one with mysql2

/usr/src/app/vendor/bundle/ruby/2.3.0/gems/activerecord-4.2.10/lib/active_record/connection_adapters/connection_specification.rb:37:in `initialize': undefined method `tr' for nil:NilClass (NoMethodError)

According to this thread https://github.com/intercom/intercom-ruby/issues/249 it could be related with my environment variables. Would it be another mistake in my command ?

Hi!

It could be that your DATABASE_URL is malformed, as the error occurs in interpreting the database connection string. You might also try dropping the port (:3306).
When you use the Docker image, the Ruby environment is fully provided, so rbenv is unlikely to be involved.

What command are you currently using to run the Foodsoft Docker image?

Regards,

  • Willem

the exact command I use is the following

docker run --name foodsoft_run -p 3000 -e SECRET_KEY_BASE='mYunBreAkaBleKEY15476147654145' -e DATABASE_URL='mysql2//root:foodsoft@my.host.net:3306/foodsoftdb?encoding=utf8' -e REDIS_URL='redis://my.host.net:6379' -e RAILS_FORCE_SSL=false   -v /var/www/app_config.yml:/usr/src/app/config/app_config.yml:ro   foodcoops/foodsoft

You’re missing the colon after “mysql2”.
Make your

Ok, looks like we made another step :

I run this
docker run --name foodsoft_prod -p 3000 -e SECRET_KEY_BASE=‘mYunBreAkaBleKEY15476147654145’ -e DATABASE_URL=‘mysql2://root:foodsoft@my.host.net:3306/foodsoftdb?encoding=utf8’ -e REDIS_URL=‘redis://my.host.net:6379’ -e RAILS_FORCE_SSL=false -v /var/www/app_config.yml:/usr/src/app/config/app_config.yml:ro foodcoops/foodsoft

and the output is now this

`/nonexistent` is not a directory.
Bundler will use `/tmp/bundler/home/unknown' as your home directory temporarily.
=> Booting Thin
=> Rails 4.2.10 application starting in production on http://0.0.0.0:3000
=> Run `rails server -h` for more startup options
=> Ctrl-C to shutdown server
Loading app configuration from config/app_config.yml
Exiting
/usr/src/app/vendor/bundle/ruby/2.3.0/gems/mysql2-0.4.10/lib/mysql2/client.rb:89:in `connect': Can't connect to MySQL server on 'vmjin.tetaneutral.net' (101 "Network is unreachable") (Mysql2::Error)
	from /usr/src/app/vendor/bundle/ruby/2.3.0/gems/mysql2-0.4.10/lib/mysql2/client.rb:89:in `initialize'
	from /usr/src/app/vendor/bundle/ruby/2.3.0/gems/activerecord-4.2.10/lib/active_record/connection_adapters/mysql2_adapter.rb:18:in `new'
	from /usr/src/app/vendor/bundle/ruby/2.3.0/gems/activerecord-4.2.10/lib/active_record/connection_adapters/mysql2_adapter.rb:18:in ` 

I have another instance of mysql on the same server, but outside of docker, may it use the same port ? How to check if it is the reason of the issue ?

Here is the filter table of my firewall

iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain FORWARD (policy DROP)
target     prot opt source               destination         
DOCKER-USER  all  --  anywhere             anywhere            
DOCKER-ISOLATION-STAGE-1  all  --  anywhere             anywhere            
ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED
DOCKER     all  --  anywhere             anywhere            
ACCEPT     all  --  anywhere             anywhere            
ACCEPT     all  --  anywhere             anywhere            

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         

Chain DOCKER (1 references)
target     prot opt source               destination         

Chain DOCKER-ISOLATION-STAGE-1 (1 references)
target     prot opt source               destination         
DOCKER-ISOLATION-STAGE-2  all  --  anywhere             anywhere            
RETURN     all  --  anywhere             anywhere            

Chain DOCKER-ISOLATION-STAGE-2 (1 references)
target     prot opt source               destination         
DROP       all  --  anywhere             anywhere            
RETURN     all  --  anywhere             anywhere            

Chain DOCKER-USER (1 references)
target     prot opt source               destination         
RETURN     all  --  anywhere             anywhere

You can use docker run (or docker exec - if container is running) with /bin/sh (or /bin/bash) to get a shell inside the container. Then you can see which hosts you can reach.
If you have a database running in docker on the same machine, you’d better use the docker ip address (e.g. use docker inspect). Perhaps you can also use its name instead as host (I’d need to look that up when running without docker-compose).

Hope that gives you a pointer.

Ok it does help thank you very much.

I had found that trick with docker inspect to use the container IP, I just wanted to make sure I was looking in the good direction. I’m quite confident now that I’ll soon have that software running ! Some news tomorrow