Mounting docker volume on specific path - docker

I am trying to deploy photo-stream (https://github.com/maxvoltar/photo-stream) using a docker container. Photo-stream is a picture publishing site meant for self-hosting. It expects its pictures in a path called 'photos/original/', relative to where it's installed. It will create other directories under 'photos/' to cache thumbnails and such.
When I populate that directory with some pictures and start the application natively (without docker) from its build directory using:
$ bundle exec jekyll serve --host 0.0.0.0
it shows me the pictures I put in that directory. When running the application inside a docker container, I need it to
mount a volume that contains a path 'photos/original' so that I can keep my pictures there. I have created this path on
a disk mounted at /mnt/data/.
In order to do that, I have added a volume line to the existing Dockerfile:
FROM ruby:latest
ENV VIPSVER 8.9.1
RUN apt update && apt -y upgrade && apt install -y build-essential
RUN wget -O ./vips-$VIPSVER.tar.gz https://github.com/libvips/libvips/releases/download/v$VIPSVER/vips-$VIPSVER.tar.gz
RUN tar -xvzf ./vips-$VIPSVER.tar.gz && cd vips-$VIPSVER && ./configure && make && make install
COPY ./ /photo-stream
WORKDIR /photo-stream
RUN ruby -v && gem install bundler jekyll && bundle install
VOLUME /photo-stream/photos
EXPOSE 4000
ENTRYPOINT bundle exec jekyll serve --host 0.0.0.0
I build the container this way:
$ docker build --tag photo-stream:1.0 .
I run the container this way:
$ docker run -d -p 4000:4000 -v /mnt/data/photos/:/photos/ --name ps photo-stream:1.0
I was expecting the content of the directory /mnt/data/photos to be shown. Instead, nothing is shown. However, a volume '/var/lib/docker/volumes/e5ff426ced2a5e786ced6b47b67d7dee59160c60f59f481516b638805b731902/_data' is created, and when that is populated with pictures, those are shown.

Related

Why Dockerfile builds but is not working correctly, even though it works manually?

I've been trying to get this running for many MANY hours. I've been scouting docker docs, github repos and other stuff but I can't get it working for some reason.
My dockerfile:
FROM mattrayner/lamp:latest-1804
WORKDIR /app
RUN wget -O /tmp/lwt.zip http://downloads.sourceforge.net/project/lwt/lwt_v_1_6_3.zip && \
yes A | unzip /tmp/lwt.zip &&\
rm /tmp/lwt.zip &&\
mv connect_xampp.inc.php connect.inc.php
EXPOSE 80
CMD ["/run.sh"]
It build normally without any errors but when I run the image nothing appears in the /app directory and I get just a basic Welcome to LAMP view on my browser.
Though,
If I do docker run -p "80:80" -it -v ${PWD}/app:/app mattrayner/lamp:latest-1804 /bin/bash, cd /app, copy and paste
wget -O /tmp/lwt.zip http://downloads.sourceforge.net/project/lwt/lwt_v_1_6_3.zip && \
yes A | unzip /tmp/lwt.zip &&\
rm /tmp/lwt.zip &&\
mv connect_xampp.inc.php connect.inc.php
it still doesn't work BUT if I exit and run the same docker run command it works.
Docker LAMP instructions also state to do exactly as I have done:
FROM mattrayner/lamp:latest-1804
# Your custom commands
CMD ["/run.sh"]
As I followed these instructions I thought that everything would work nicely.
What's the catch here? It has something to do with the intermediate containers probably but I can't comprehend it (I'm not a devops or developer by trade, just a hobbyist).
That happens because you're doing this:
Download a file (wget ...) in your /app dir in your docker image.
After that, you're overwritting this /app dir when you mount volume, with content of your $PWD/app.
If you are installing something doing docker build in some dirs, don't mount into the same path.
If you need something in the same path, you can mount some concrete files, but not the whole dir, or it will override what you had in your docker image when container is created.
You can do wget somewhere else or download it into your ${PWD}/app and then mount it.

Creating first docker container: Can't find host system file on build

I'm trying to bundle my Jekyll blog as a docker container.
I found this Dockerfile which seems to suit my use case but wanted to be more hands on so I copied it directly into my repo:
FROM ruby:latest
MAINTAINER Peter Etelej <peter#etelej.com>
RUN apt-get -qq update && \
apt-get -qq install nodejs -y && \
gem install -q bundler
RUN mkdir -p /etc/jekyll && \
printf 'source "https://rubygems.org"\ngem "github-pages"\ngem "execjs"\ngem "rouge"' > /etc/jekyll/Gemfile && \
printf "\nBuilding required Ruby gems. Please wait..." && \
bundle install --gemfile /etc/jekyll/Gemfile --clean --quiet
RUN apt-get clean && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
ENV BUNDLE_GEMFILE /etc/jekyll/Gemfile
EXPOSE 4000
ENTRYPOINT ["bundle", "exec"]
CMD ["jekyll", "serve","--host=0.0.0.0"]
When I run it I get an error
jekyll 3.4.3 | Error: No such file or directory # rb_sysopen - /etc/modules-load.d/modules.conf
The host system has this file but my assumption was that the container didn't have access to it so I tried to add it into the Dockerfile
ADD /etc/modules-load.d/modules.conf /etc/modules-load.d/modules.conf
I then docker build and get the error
lstat etc/modules-load.d/: no such file or directory
I don't understand why the container is looking for this file in the first place but I'm even more confused by the fact that I can't add a file which is clearly there.
Docker builds run on the docker host, not necessarily the client where you run the command, and so all the files needed to run the build are sent in the build context to the host. That context is most often the current directory, or ., that you pass at the end of the docker build -t $image_name . command.
Everything that you try to include in the image with a COPY or ADD is done in reference to that build context, not the filesystem on your client or host machine. So if you need a modules.conf, you'll need to first copy that into your directory with the Dockerfile, and then COPY the file from there.
As for why jekyll is looking for the file, I'm not familiar with jekyll, but it doesn't look promising for something running inside of a container. The modules are kernel specific and containers are designed to be moved to different hosts with potentially different kernels.

Running bower install inside a docker volume

Context
So I'm trying to execute build a polymer project inside a docker container as a volume (to access it I'm using docker run (...) --volume="/var/www/html:/var/www/html" --volumes-from="my-polymer-image-name" my-nginx-image).
And I tried execute the following Dockerfile, but declaring the volume last, but the volume was empty when I tried to access it from "my-nginx-container" (docker exec -ti my-nginx-image-name /bin/sh).
So I thought I had to declare the volume before using using it.
Problem
But when I tried to install my bower components, I noticed that no bower_components directory was being created.
########################################################
# Dockerfile to build Polymer project and move to server
# Based on oficial node Dockerfile
########################################################
FROM node:6
VOLUME /var/www/html
# Install polymer and bower
RUN npm install -g \
polymer-cli \
bower
# Add project to a temp folder to build it
RUN mkdir -p /var/www/html/temp
COPY . /var/www/html/temp
WORKDIR /var/www/html/temp
RUN ls -la
RUN bower install --allow-root # here is where I try to build my project
RUN polymer build
# Move to release folder
WORKDIR /var/www/html
RUN mv /var/www/html/temp/build/unbundled/* /var/www/html
RUN bower install --allow-root
# Remove temporary content
RUN rm -rf /var/www/html/temp
Volume mount when docker image build done.
in last row in Docker file add
ENTRYPOINT ["/bin/bash", "/etc/entrypoint.sh"]
Use entripoint script like this.
#!/bin/bash
set -e #if error bash script will exit and stop docker image
cd /var/www/html/
bower install --allow-root
polymer build
mv /var/www/html/temp/build/unbundled/* /var/www/html
rm -rf /var/www/html/temp

Docker : oci runtime error: exec: "/bin/bash": stat /bin in windows 7

I am using windows 7. In my home folder I made a new directory Docker. And inside that I made new directory rails.
This is my docker file: (Docker/rails/Dockerfile)
FROM alpine:3.2
MAINTAINER xxx <xxx#xxx.in>
ENV BUILD_PACKAGES bash curl-dev ruby-dev build-base
ENV RUBY_PACKAGES ruby ruby-io-console ruby-bundler
# Update and install all of the required packages.
# At the end, remove the apk cache
RUN apk update && \
apk upgrade && \
apk add $BUILD_PACKAGES && \
apk add $RUBY_PACKAGES && \
rm -rf /var/cache/apk/*
RUN mkdir /usr/app
WORKDIR /usr/app
COPY Gemfile /usr/app/
COPY Gemfile.lock /usr/app/
RUN bundle install
COPY . /usr/app
And then I changed directory to Docker. On ls it shows rails.
Then I typed this command:
docker build rails
Now the image name is alpine. I made a tag to rails like this:
docker tag <imageid> myname/rails
Problem:
The image is successfully build and I have a repository rails and pushed it successfully. I am able to pull it as well.
Till now everything is fine, but then I run this command:
docker run -i -t xxx/rails /bin/bash
It gives me this error:
C:\Program Files\Docker Toolbox\docker.exe: Error response from daemon: oci runtime error: exec: "/bin/bash": stat /bin/bash: no such file or directory.
So I am stuck there.
My Objective:
I want to run this command successfully:
rails -v
To run that command I need to install the image, and I don't know how to install the image, I have been following up numerous tutorials since last week.
I am new to docker. This is my first docker image.
Edit:
docker exec -it sh
Alpine does not come with bash by default, only /bin/sh so you should change your command to:
docker run -i -t vikaran/rails sh
Also worth noting you can run:
docker build -t myname/rails rails
To automatically tag the image when building it.

How can I mount a volume from a data container while preserving the owner and permissions?

I'm using Fig and attempting to use a data volume container to share uploaded files between a Rails web server and a Resque worker running in another container. To do this the data volume container defines a /rails/public/system volume which is meant to be used to share these files. The Rails and Resque processes run as a rails user in their respective containers which are both based of the markb/litdistco image. All together the fig.yml looks like this:
redis:
image: redis:2.8.17
volumes_from:
- file
web:
image: markb/litdistco
command: /usr/bin/start-server /opt/nginx/sbin/nginx
ports:
- 80:8000
- 443:4430
environment:
DATABASE_URL:
links:
- redis
volumes_from:
- file
worker:
image: markb/litdistco
command: /usr/bin/start-server "bundle exec rake environment resque:work QUEUE=litdistco_offline RAILS_ENV=production"
environment:
DATABASE_URL:
links:
- redis
volumes_from:
- file
file:
image: markb/litdistco
command: echo "datastore"
volumes:
- /var/redis
- /rails/log
- ./config/container/ssl:/etc/ssl
When the web and worker containers are running, I can see the /rails/public/system directory in both, however it is owned by the root user in both containers and the permissions on the directory prevent the rails user from writing to this directory.
For reference there are two Dockerfiles which go into making the markb/litdistco container. The first defines a base image I use for local development (Dockerfile):
# This Dockerfile is based on the excellent blog post by SteveLTN:
#
# http://steveltn.me/blog/2014/03/15/deploy-rails-applications-using-docker/
#
# KNOWN ISSUES:
#
# * Upgrading passenger or ruby breaks nginx directives with absolute paths
# Start from Ubuntu base image
FROM ubuntu:14.04
MAINTAINER Mark Bennett <mark#burmis.ca>
# Update package sources
RUN apt-get -y update
# Install basic packages
RUN apt-get -y install build-essential libssl-dev curl
# Install basics
RUN apt-get -y install tmux vim
RUN apt-get install -y libcurl4-gnutls-dev
# Install libxml2 for nokogiri
RUN apt-get install -y libxslt-dev libxml2-dev
# Install mysql-client
RUN apt-get -y install mysql-client libmysqlclient-dev
# Add RVM key and install requirements
RUN command curl -sSL https://rvm.io/mpapis.asc | gpg --import -
RUN curl -sSL https://get.rvm.io | bash -s stable
RUN /bin/bash -l -c "rvm requirements"
# Create rails user which will run the app
RUN useradd rails --home /rails --groups rvm
# Create the rails users home and give them permissions
RUN mkdir /rails
RUN chown rails /rails
RUN mkdir -p /rails/public/system
RUN chown rails /rails/public/system
# Add configuration files in repository to filesystem
ADD config/container/start-server.sh /usr/bin/start-server
RUN chown rails /usr/bin/start-server
RUN chmod +x /usr/bin/start-server
# Make a directory to contain nginx and give rails user permission
RUN mkdir /opt/nginx
RUN chown rails /opt/nginx
# Switch to rails user that will run app
USER rails
# Install rvm, ruby, bundler
WORKDIR /rails
ADD ./.ruby-version /rails/.ruby-version
RUN echo "gem: --no-ri --no-rdoc" > /rails/.gemrc
RUN /bin/bash -l -c "rvm install `cat .ruby-version`"
RUN /bin/bash -l -c "gem install bundler --no-ri --no-rdoc"
# Install nginx
RUN /bin/bash -l -c "gem install passenger --no-ri --no-rdoc"
RUN /bin/bash -l -c "passenger-install-nginx-module"
ADD config/container/nginx-sites.conf.TEMPLATE /opt/nginx/conf/nginx.conf.TEMPLATE
ADD config/container/set-nginx-paths.sh /rails/set-nginx-paths.sh
RUN /bin/bash -l -c "source /rails/set-nginx-paths.sh"
# Copy the Gemfile and Gemfile.lock into the image.
# Temporarily set the working directory to where they are.
WORKDIR /tmp
ADD Gemfile Gemfile
ADD Gemfile.lock Gemfile.lock
# bundle install
RUN /bin/bash -l -c "bundle install"
# Add rails project to project directory
ADD ./ /rails
# set WORKDIR
WORKDIR /rails
# Make sure rails has the right owner
USER root
RUN chown -R rails:rails /rails
# Publish ports
EXPOSE 3000
EXPOSE 4430
EXPOSE 8000
This is tagged as the litdistco-base image, then I use config/containers/production/Dockerfile to generate the image that I tag as markb/litdistco and run in staging and production.
# Start from LitDistCo base image
FROM litdistco-base
MAINTAINER Mark Bennett <mark#burmis.ca>
USER rails
# Setup volumes used in production
VOLUME ["/rails/log", "/rails/public/system"]
# Build the application assets
WORKDIR /rails
RUN /bin/bash -l -c "touch /rails/log/production.log; chmod 0666 /rails/log/production.log"
RUN /bin/bash -l -c "source /etc/profile.d/rvm.sh; bundle exec rake assets:precompile"
Can anyone possibly explain how I can get the data container volume to mount as writeable by the rails user. I'd very much like to avoid running any of the Ruby processes as root, even inside a container.
For some context I should also mention that I'm developing the images in Docker in boot2docker on Mac OS X, then running them on a Google Compute Engine instance on an Ubuntu 14.04 host. Thanks!
I would modify your image a little bit. Write a shell script that wraps the /usr/bin/start-server command in your fig.yml and place that inside your container.
Then you can chown rails anything that you need before starting up your server.
Running the container with a default user rails is not really needed either, as long as you start up the server as the rails user: sudo -u rails /usr/bin/start-server (or something like that).
Personally haven't used the litdistco-base image yet, so do not know all the specifics on how it works.
I think you need to modify the litdistco-base image in the following way so both directories are owned by rails:
# Start from LitDistCo base image
FROM litdistco-base
MAINTAINER Mark Bennett <mark#burmis.ca>
RUN mkdir -p /rails/log
RUN mkdir -p /rails/public/system
RUN chown -R rails:rails /rails/log /rails/public/system
USER rails
# Setup volumes used in production
VOLUME ["/rails/log", "/rails/public/system"]
# Build the application assets
WORKDIR /rails
RUN /bin/bash -l -c "touch /rails/log/production.log; chmod 0666 /rails/log/production.log"
RUN /bin/bash -l -c "source /etc/profile.d/rvm.sh; bundle exec rake assets:precompile"

Resources