How to avoid redundancy and time loss when re-building images during development? - deployment

As a Vagrant user, when trying Docker I noticed one significant difference between development workflow with Vagrant and with Docker - with Docker I need to rebuild my image every time from scratch, even if I made minor changes in code.
This is major problem for me, because the process of image rebuilding oftenly very redundant and time consuming.
Perhaps there are some smart workflows with Docker already invented, if so, what are they?

I filed a feature-request for the vagrant-cachier plugin for saving docker build data and attached a bash workaround for that process. If it's okay for you to hack yourself around you can implement the scripts in vagrant.
caching docker build data with vagrant
Note that this procedure needs the vagrant-cachier plugin to be installed and has to save and load +300MB files from disk if they are new to the machine. Thus it's really slow if you have dockerfiles with just 1-5 lines of code but it's fast if you have dockerfiles with a lot of LOCs or images that have to be downloaded from the net.
Also note that this approach saves every intermediate building step. So if you are building an image and change a line in the middle of a dockerfile and build again the docker build process will get all cached intermediate containers till the changed line.
Using baseimages is still the preferred way but you can combine both procedures.
Feel free to post improvements and subscribe so fgrehm will maybe implement this in his plugin natively.

As Mark O'Connor suggested, one of the tips may be building a base image to your container(s). This image should have the dependencies, package installation, downloads... or any other consuming activity. This base image should be supposed to be built less frequently than the other one(s). In a similar way, if the final states of the execution of each step of your dockerfile doesn't change, Docker don't build this layer again. Thus, you can trying execute the commands than may change this state almost every run (e.g.: apt-get update) as later as you can, so docker don't have to rebuild the steps before. And also you can try to edit your dockerfiles in the later steps better than in the first.
Another option if you compile/download something inside the container is to have it downloaded or compiled in a host folder, and attach it to the container using -v or --volume option in docker run.
Finally there is other approaches to this issue as the one used by chef with knife container. In this approach you build the container using chef cookbooks, and each time you build it (because you have edited your cookbooks...) these changes are applied as a new docker layer (AUFS layer) and you don't have to repeat all the process. I didn't recommend this solution unless you have experience with Chef and you have cookbooks to manage your software. You should work harder to get it working and if you want Chef only to manage docker containers I think it doesn't worth it (although chef is a great option to manage infrastructures).
To automate the building process in case you have several images dependents itself, you can have a bash script that helps you with that task (credits to smola#github):
#!/bin/bash
IMAGES="${IMAGES:-stratio/base:test stratio/mesos:test stratio/spark-mesos:test stratio/ingestion:test}"
LATEST_TAG="${LATEST_TAG:-test}"
for image in $IMAGES ; do
USER=${image/\/*/}
aux=${image/*\//}
NAME=${aux/:*/}
TAG=${aux/*:/}
DIR=${NAME}/${TAG}
pushd $DIR
docker build --tag=${USER}/${NAME}:${TAG} .
if [[ $TAG = $LATEST_TAG ]] ; then
docker tag ${USER}/${NAME}:${TAG} ${USER}/${NAME}:latest
fi
popd
done

There are a couple of tricks that might better your workflow (very web-focused)
Docker caching
Always make sure you are adding your source to your Docker image in Dockerfile at the very end.
Example;
COPY data/package.json /data/
RUN cd /data && npm install
COPY data/ /data
This will make sure you get optimal caching when building the image, and that Docker doesn't have to rebuild the npm packages when you are changing your source.
Also, make sure you don't have a base-image that adds folders/files that are often changed (like base images doing COPY . /data/
fig mount
Use fig (or another tool), and mount your source directory when developing. This way, you can develop with instant changes and still use the current version of your code when building the image.
development server
You can start your developer web-server when you are developing, and nginx when not (if you are developing an www app, but same idea applies to other apps).
Example, in your startup script, do something like:
if [[ $DEBUG ]]; then
/usr/bin/supervisorctl start gulp
else
/usr/bin/supervisorctl start nginx
fi
And have autostart=false in your supervisord.conf files.
auto-refresh app
If you are developing a web-app, use tools like gulp and eg gulp-connect, if you are developing a python/django app, use the runserver utility. Both reloads the server when detecting changes in the files.
If you are using the if [[ $DEBUG ]] ... trick, make them listen on the same port as your normal instance (nginx). That way, you can have 1 configuration for your reverse proxy, ie, just send the traffic to example www:8080, it will hit your web-page both in production and if you are developing.

Create a based image that holds the bulk of your application's dependencies. This will significantly reduce your docker build times.

Related

Running mapbox-gl-js locally (unable to serve debug page)

Edit:
Summary, I tried to follow only the steps listed in the below two links as applies to windows:
https://github.com/mapbox/mapbox-gl-js/blob/master/CONTRIBUTING.md
https://github.com/stackgl/headless-gl#windows
Here I have reattached the screenshot of the commands that I had problems with:
https://imgur.com/RCQCNU5
One more step I took that I should mention is I also did not find the headless gl when I downloaded the repository, when the install headless gl command did not work I manually copied the file and put it in my local copy under the nodemodules directory thinking it would work but it didnt solve anything. I do think this is related to access issues but I dont know what else I should try to get it working?
First, let's clarify your problem: you want a version of mapbox-gl.js which contains a recently fixed bug.
Your best option is to just wait a couple of weeks for a release.
Failing that, you should build your own, from master. You don't need to set up a debug server for that. You can skip straight to the "Creating a Standalone Build" section.
If the steps for building on Windows don't work for some reason, you could set up a local virtual machine running Ubuntu and use that.
But honestly, just wait a couple of weeks. :)
Just in case some one else need to run this on local server.
After clone
Run npm install
npm run start-debug
It will start listening on port 9966.
Test the debug html files entering to
localhost:9966/debug/FILE_NAME_TO_TEST.html

How to make RubyMine use already-running docker-compose service, rather than trying to start it?

I'm using docker-compose on a Rails project, with the main web service being called web.
When I try to run a test from RubyMine, it attempts to run
/usr/local/bin/docker-compose -f
/Users/jy/Development/#Rails/project/docker-compose.yml -f
/Users/jy/Library/Caches/RubyMine2018.3/tmp/docker-compose.override.35.yml
up --exit-code-from web --abort-on-container-exit web
Even though the web container is already up.
This leads to issues with duplicate networks being created, and the web service being stopped afterward thanks to the --abort-on-container-exit.
How can I make RubyMine run my tests using a simple docker-compose exec web bundle exec rspec …, without all the preamble? I know that command works because it works from the command line (but running an individual test involves a lot of typing to fill in --example testname!)
Apparently, it doesn't support this yet.
https://youtrack.jetbrains.com/issue/RUBY-19849 is the issue that needs resolving in order to make it work properly.

Can you generate and apply patches to a docker container offline?

We're looking into replacing our update system with docker, but we have a unique constraint where all upgrades need to happen offline. The use case is very similar to how you would update router firmware or something from a LAN not connected to the internet.
Currently our users download a patch file, which they then upload to the web interface of our system over a private LAN. Our system applies the patch. It is all implemented with the diff and patch commands. We do the diffing because our codebase is pretty giant but relatively few files change from version to version.
We think switching to docker can help us tremendously for our development, but for production and our update system we need to make sure we can do offline, diff-based updates.
My question boils down to this: are there docker analogs to the diff and patch commands that can be used to update a container offline?
I know docker has commands like docker diff, but as per the documentation it just shows a list of files that have been added, removed or changed from a container. docker save and docker export look like they come close though, but they provide full images whereas I'm after a diff. Similarly there seems to be no way as far as I can tell to use docker load to load a diff.
Thanks!
IMHO you should use private registry for this. Docker image can contain many layers so your update will be just small layer users need to download. Also updating image on local system doesn't affect running containers, so your users will just download new layers on update and then restart running containers from new image. This will be almost same as patch system. So in short from user side it will look like this:
docker pull new layers from your private registry instance (need to be online)
docker stop old container (offline)
docker run new container from updated image
All config files should be stored outside image for example in a docker volume.

Rackup to use Thin instead of WEBrick

New to Sinatra, just development server up and running but rackup is using WEBrick instead of Thin, Thin gem is already installed, this has to be a simple configuration tweak but I don't know where. Oh while you are at it, does Thin auto-refresh when I change the source code? It appears that I have to stop and restart WEBrick when I make source code changes.
EDIT
As suggested, thin start works with a tweak for my setup. By itself, it throws an error "start_tcp_server": no acceptor (RuntimeError) which means I already have another service running on that port. To resolve the issue, I simply run thin start -p 9292. Hope this helps someone else.
I believe you'll likely just want to start up thin via something like:
bundle exec rackup -s thin
If you're on OSX you might want to check out Pow for your development environment.
For reloading files between requests: How to get Sinatra to auto-reload the file after each change?
You can start the server with Thin using just $ thin start.
If you want code reloading, use one of the several reloading libraries in the wild: Shotgun (which will fork and exit for every request, does not work on Windows), Rack Reloader (which is a Rack middleware) or Sinatra Reloader. I personally favor Sinatra Reloader, since it just reloads files that have changed and is therefore faster. Also there's the possibility to add additional files which shall be reloaded and files that must not be reloaded.

Perl catalyst application modification

So I am attempting to modify an application written by another programmer. The program is written in Perl and apparently uses the Catalyst framework neither of which I have any experience with.
The code is well documented and my modifications seem pretty straightforward however when I try to change something (in the the controllers to be specific) the same to take no effect. Am I missing a step? I open the file edit it, save it, and try to load the web app in my browser. I've even deleted the entire contents of one of the controllers to see if it would break the application and it did not.
Please Help.
Thanks,
Ken
If the application was set-up in a sane way (using uri_for(_action) in templates and not specifically relying on the server/env/etc) you should be developing with the dev server. There are some practices that can make this difficult:impossible without modifications. This is all you should have to do–
cd {APPLICATION DIRECTORY}
# Read about it-
perldoc script/*_server.pl
# Run it-
script/*_server.pl -r -d
Unless there is something wonky in the setup, you’ll get http://localhost:3000/ running with your app.
Or, what is probably a good idea, run the application as the webuser in your apache setup. If there are files or access expected to be for that user, it might be important (e.g., if session or cache files are used and restricted to the user)–
sudo -u www script/*_server.pl -r -d
The flags turn on debugging output and the restarter so that every time you change files in the application, the server will restart automatically (if it compiles).
Catalyst is a joy to develop with and the dev server is part of why.