Skip to content

Instantly share code, notes, and snippets.

@palkan
Last active January 15, 2024 10:32
Show Gist options
  • Save palkan/cf18e235fd4d65abc84528bd49beafa4 to your computer and use it in GitHub Desktop.
Save palkan/cf18e235fd4d65abc84528bd49beafa4 to your computer and use it in GitHub Desktop.
Docker Dev

Installation

Go to the official website and choose your OS.

MacOS

Docker for Mac has a problem is the disk IO performance (see docker/for-mac#77).

There is a fix (https://github.com/IFSight/d4m-nfs) which makes Docker use NFS instead of OSXFS.

NOTE: MacOS High Sierra <10.3.2 is likely to have problems with NFS (see discussion).

NOTE: Docker for Mac 17.09.1 is the last working version (see mineshaftgap/d4m-nfs#55).

Follow the instructions:

  1. Update docker File Sharing preferences as explained at https://github.com/IFSight/d4m-nfs (i.e. only /tmp directory should remain)

  2. Quit Docker

  3. Clone repo:

git clone https://github.com/IFSight/d4m-nfs ~/d4m-nfs
  1. Put the following configuration in ~/d4m-nfs/etc/d4m-nfs-mounts.txt:
/Users:/Users
/Volumes:/Volumes
/private:/private
  1. Run the script:
~/d4m-nfs/d4m-nfs.sh

6*) Optional Add shortcut to run d4m-nfs:

echo "#\!/usr/bin/env bash\n/Users/`whoami`/d4m-nfs/d4m-nfs.sh" > /usr/local/bin/d4m
chmod +x /usr/local/bin/d4m

And then just run d4m to start Docker.

NOTE: it requires root access to modify /etc/exports, /etc/nfs.conf, etc.

That's it.

NOTE: now you must start Docker using the same script (~/d4m-nfs/d4m-nfs.sh or d4m) in order it to work correctly.

File Watchers

D4M-NFS doesn't support FS events, but there are the workarounds for popular text editors (instructions).

Usage

Add Dockerfile to build you application and docker-compose.yml to configure services (see examples below).

Basic commands:

# build app container
docker-compose build app

# run setup script (bundle install, db:migrate, db:seed)
docker-compose run runner -c ./bin/setup

# setup frontend dependencies
docker-compose run webpack -c 'npm install'

# run web app
docker-compose up web

# run sidekiq
docker-compose up sidekiq

# run the whole app
docker-compose up web webpack sidekiq

# run specs
docker-compose run web rspec

# simply launch bash within app directory
docker-compose run runner

Usually, the runner container is always running and you're working within it (install gems, run generators, tests, etc). So, docker-compose run runner is like vagrant ssh.

Using multiple configs

Sometimes it's useful to have separate docker-compose configurations (e.g. when working with microservices). You can re-use some services (e.g. databases) by passing several configuration files:

docker-compose -f docker-compose.yml -f docker-compose-service.yml up web webpack sidekiq another_app

Useful Aliases

alias dcr='docker-compose run --rm'
alias dcu='docker-compose up'
alias dcs='docker-compose stop'
alias dstats='docker stats --format "table {{.Name}}:\t{{.MemUsage}}\t{{.CPUPerc}}"'

Webpack Dev Server Configration

Webpack config:

devServer: {
  contentBase: paths.dest,
  clientLogLevel: 'warning',
  disableHostCheck: true,
  headers: { 'Access-Control-Allow-Origin': '*' },
  inline: true,
  overlay: true,
  port: 3100,
  publicPath: '/front/',
}

Rails helper:

def webpack_bundle_tag(bundle, options = {})
  host = Rails.env.development? ? ENV['WEBPACK_URL'] : compute_asset_host
  bundle_tag = javascript_include_tag("#{host}/front/#{Webpack.entry_path(bundle)}", options)

  if bundle == 'shared' && (manifest = Webpack.manifest)
    "#{javascript_tag "window.webpackManifest = #{manifest};"}\n#{bundle_tag}".html_safe
  else
    bundle_tag
  end
end
version: '3.4'
services:
app: &app
build:
context: .
dockerfile: ./Dockerfile
args:
PG_VERSION: '9.5'
NODE_VERSION: '8.11.1'
YARN_VERSION: '1.7.0'
image: my-project-dev:1.0.0
volumes:
- .:/app:cached
tmpfs:
- /tmp
backend: &backend
<<: *app
stdin_open: true
tty: true
volumes:
- .:/app:cached
- rails_cache:/app/tmp/cache
- bundle:/bundle
- node_modules:/app/node_modules
- assets:/app/public/assets
environment:
- RAILS_ENV=${RAILS_ENV:-development}
- REDIS_URL=redis://redis:6379/
- DATABASE_URL=postgres://postgres:postgres@postgres:5432
depends_on:
- postgres
- redis
runner:
<<: *backend
command: /bin/bash
ports:
- '3000:3000'
web:
<<: *backend
command: rails server -b 0.0.0.0
ports:
- '3000:3000'
sidekiq:
<<: *backend
command: sidekiq -q mailers -q default -q notifier
postgres:
image: postgres:9.5
volumes:
- .docker/.psqlrc:/root/.psqlrc:ro
- postgres:/var/lib/postgresql/data
- postgres_history:/var/log/psql_history
ports:
- 5432
redis:
image: redis:3.2-alpine
volumes:
- redis:/data
ports:
- 6379
volumes:
postgres:
postgres_history:
redis:
bundle:
node_modules:
assets:
rails_cache:
# Example docker-compose for a sub-service
version: '3'
services:
# If you have another app and want to share
# some resources
another_app:
build:
# path to another app root (and Dockerfile)
context: '../another-app'
image: another-app:1.1
command: bundle exec sidekiq
environment:
- REDIS_URL=redis://redis:6379/
volumes:
- ../another-app:/app
# Here we use services and volumes defined in the main config
- bundle:/bundle
depends_on:
- redis
FROM ruby:2.5.1
ENV PG_MAJOR 10
# for PostgreSQL
RUN echo 'deb http://apt.postgresql.org/pub/repos/apt/ stretch-pgdg main' $PG_MAJOR > /etc/apt/sources.list.d/pgdg.list
RUN wget --quiet https://www.postgresql.org/media/keys/ACCC4CF8.asc
RUN apt-key add ACCC4CF8.asc
RUN apt-get update && apt-get install -y build-essential
RUN apt-get install -y libpq-dev apt-utils postgresql-client-$PG_MAJOR
COPY .nvmrc /tmp/.nvmrc
RUN curl -L https://git.io/n-install | bash -s -- -q -y - && $HOME/n/bin/n $(cat /tmp/.nvmrc) && rm /tmp/.nvmrc
COPY package.json /tmp/package.json
RUN curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version $( \
cat tmp/package.json | \
grep '\"yarn\":' | \
awk -F: '{ print $2 }' | \
sed 's/\"//g') && \
rm /tmp/package.json
RUN mkdir -p /app
WORKDIR /app
ENV LANG C.UTF-8
ENV GEM_HOME /bundle
ENV BUNDLE_PATH $GEM_HOME
ENV BUNDLE_APP_CONFIG=$BUNDLE_PATH \
BUNDLE_BIN=$BUNDLE_PATH/bin \
BUNDLE_JOBS=4 \
BUNDLE_RETRY=3
ENV PATH /app/bin:$BUNDLE_BIN:$PATH
EXPOSE 3000
ENTRYPOINT ["bundle", "exec"]
CMD ["rails", "server", "-b", "0.0.0.0"]
#!/usr/bin/env bash
OS=`uname -s`
if [ $OS != "Darwin" ]; then
echo "This script is OSX-only. Please do not run it on any other Unix."
exit 1
fi
if [[ $EUID -eq 0 ]]; then
echo "This script must NOT be run with sudo/root. Please re-run without sudo." 1>&2
exit 1
fi
echo ""
echo " +-----------------------------+"
echo " | Setup native NFS for Docker |"
echo " +-----------------------------+"
echo ""
echo "WARNING: This script will shut down running containers."
echo ""
echo -n "Do you wish to proceed? [y]: "
read decision
if [ "$decision" != "y" ]; then
echo "Exiting. No changes made."
exit 1
fi
echo ""
if ! docker ps > /dev/null 2>&1 ; then
echo "== Waiting for docker to start..."
fi
open -a Docker
while ! docker ps > /dev/null 2>&1 ; do sleep 2; done
echo "== Stopping running docker containers..."
docker-compose down > /dev/null 2>&1
docker volume prune -f > /dev/null
osascript -e 'quit app "Docker"'
echo "== Resetting folder permissions..."
U=`id -u`
G=`id -g`
sudo chown -R "$U":"$G" .
echo "== Setting up nfs..."
LINE="/Users -alldirs -mapall=$U:$G localhost"
FILE=/etc/exports
sudo cp /dev/null $FILE
grep -qF -- "$LINE" "$FILE" || sudo echo "$LINE" | sudo tee -a $FILE > /dev/null
LINE="nfs.server.mount.require_resv_port = 0"
FILE=/etc/nfs.conf
grep -qF -- "$LINE" "$FILE" || sudo echo "$LINE" | sudo tee -a $FILE > /dev/null
echo "== Restarting nfsd..."
sudo nfsd restart
echo "== Restarting docker..."
open -a Docker
while ! docker ps > /dev/null 2>&1 ; do sleep 2; done
echo ""
echo "SUCCESS! Now go run your containers 🐳"
version: '3'
services:
app: &app
build: .
image: common-dev:1.0
volumes:
- nfsmount:/app
backend: &backend
<<: *app
volumes:
- nfsmount:/app
- bundle:/bundle
# ...
volumes:
# ...
nfsmount:
driver: local
driver_opts:
type: nfs
o: addr=host.docker.internal,rw,lock,hard,nointr,nfsvers=3
device: ":${PWD}/"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment