Recently I have the case where I have to use a base Docker image from a remote or local repository. I love to keep the configuration close and to not have a couple of configuration files with the same content so I decided to write a simple program which will do the config switch and then will return it back (if needed)

Here is an example of usage:

When I build the images locally I want to use:

FROM anaconda-environment:latest

When I want to build from our CI/CD server I would like to use the remote ECR

CONFIG->remote-images:FROM XXXXXXXXXXX.dkr.ecr.us-east-1.amazonaws.com/anaconda-environment:latest

Then in the Docker file, I put those lines

# CONFIG->local-images:FROM anaconda-environment:latest
# CONFIG->remote-images:FROMXXXXXXXXXXX.dkr.ecr.us-east-1.amazonaws.com/anaconda-environment:latest
FROM anaconda-environment:latest
ENV ACCEPT_INTEL_PYTHON_EULA=yes
.... and so on...

And here is how the config is changed to point to the remote-images

ruby switch-config.rb Dockerfile remote-images

and this is how it is changed back to local images.

ruby switch.rb Dockerfile local-images

So far I haven’t found any drawback on this approach. For sure there is some drawbacks please let me know if you hit it.

And here is the code…

#!/usr/bin/env ruby

# ruby switch.rb Dockerfile remote-images
#
# # CONFIG->local-images:FROM anaconda-environment:latest
# # CONFIG->remote-images:FROM XXXXXXXXXXX.dkr.ecr.us-east-1.amazonaws.com/anaconda-environment:latest
# FROM anaconda-environment:latest




file = ARGV[0] || "Dockerfile"
desired_environment = ARGV[1] || "local"
lines = File.read(file).split("\n")
tag = /\s*?#\s+CONFIG->([\w\-]+?):(.*)\Z/
new_lines = []
key_found = true
options = {}
found_config_lines = false

lines.each do |line|
  if line =~ tag
    environment_key = $1
    option = $2
    options[environment_key] = option
    found_config_lines = true
  end

  if found_config_lines && options.values.include?(line)
    key_found = options.key?(desired_environment)
    new_lines << options[desired_environment]
    found_config_lines = false
    options = {}
  else
    new_lines << line
  end
end

if key_found
  File.write(file, new_lines.join("\n"))
else
  puts "Something is wrong - key not found! The syntax for defining options is:"
  puts "# CONFIG->KEY:The content of this option"
end