Skip to content

Instantly share code, notes, and snippets.

@vik-y
Last active August 27, 2017 08:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vik-y/4cc213bd692a83839f6b3c6cf0054a18 to your computer and use it in GitHub Desktop.
Save vik-y/4cc213bd692a83839f6b3c6cf0054a18 to your computer and use it in GitHub Desktop.
Design document to explain the changes done in amahi codebase

Design Document

Amahi now supports Docker. It is an open source software for automating the deployment of applications inside software containers. A container image is a lightweight, stand-alone, executable package of a piece of software that includes everything needed to run it: code, runtime, system tools, system libraries, settings.

For more information related to contianers refer to : https://www.docker.com/what-container

The idea was to get/build images of different applications and run them using docker on the hda. The benefit of using containers as opposed to the earlier method is that each container runs in an isolated environment. So they can each have different versions of different applications. For example we can have an app running on php5 and another app running on php7. Using this method if we had an image available for an app then we can directly run it using docker without any problems.

Architecture Overview : How it works? Diagram Explain the flow.

Lets assume we are trying to run multiple container apps. Let them be App1, App2, App3 and App4.

NOTE: Each app will have its own networking stack and hence can run a service on any port that they want.

App1 - 9000, 80 App2 - 8000, 80 App3 - 5000, 80 App4 - 22, 80

Each app has a web server running on port 80 (let’s assume) and they have some other service running on different ports. There can be multiple services running on different ports.

We want the web interface of each of the app to be accessible to a user. Assume a user is running their HDA at IP address: 192.168.56.105 and domain amahi.net

They want to access App1 at app1.amahi.net, App2 at app2.amahi.net and so on. Inside the HDA each app is running inside an isolated environment with their own networking stack and hence they are not reachable from the outside world. So how do we work around this problem? The answer to that is reverse proxy.

We have apache running on our HDA which handles all the requests coming on *.amahi.net. So for container apps we bind their web server port with a port on the host.

App1 -> 80 binds to -> 35001 on host App2 -> 80 binds to -> 35002 on host App3 -> 80 binds to -> 35003 on host App4 -> 80 binds to -> 35004 on host

This “binding” is similar to port forwarding. Docker by default runs these containers on a separate network and each of those containers have an IP address (local, accessible only inside the host machine) and run their own networking stack.

Once the port binding is complete if we access -> http://192.168.56.105:35001 we should get the web interface of App1 and so on. But for our users we want the app to be reachable at app1.amahi.net. So earlier the hda used to create a virtual host file for each app which used to run the relevant app server based on the url. For container apps, the present approach does this:

The apache running on host reverse proxies all requests coming on http://app1.amahi.net to http://localhost:35001 , This way for the user the url is http://app1.amahi.net and they can still access the web interface of the app.

Files Modified

Following files have been modified or added.

Gemfile # Added gem docker-api                                           
Gemfile.lock                                    
app/models/app.rb # container installation function added
app/models/webapp.rb # Reverse proxy implementation                     
config/database.yml                         
config/initializers/tmpdir.rb                   
db/schema.rb                                   
db/seeds.rb                                   
misc/webapps/app-container.conf # Handles reverse proxy configuration of containerised apps              
misc/webapps/app-php5.conf                       
spec/models/app_spec.rb # Test cases                           

# A set of scripts to test container app installation and uninstallation         
test/iteration_test.rb                 
test/test.rb                                     
test/uninstall.rb                                

Brief overview of code

The container app installation is triggered using a function : install_container_app in app/models/app.rb.

The installation process remains the same and follows the same flow of control as before.

script/install-ap calls install_bg function in app.rb and that takes care of the app installation.

In install_bg function we check if the app type is container and if yes then the rest is managed by install_container_app function. If it's not a container type app then see the else statement, where we just create a webapp for normal app.

if installer.kind.include? "container"
				# Try installing the container app
				# Mark the installation as failed if it returns false
				# For container app webapp creation will be handled inside the "install_container_app" function
				if !install_container_app(installer, webapp_path, identifier)
					self.install_status = 999
				end
			else
				# Create the webapp normally if its not a container app
				self.create_webapp(:name => name, :path => webapp_path, :deletable => false, :custom_options => installer.webapp_custom_options, :kind => installer.kind)
			end

For container type apps the webapp creation is handled by the install_container_app function itself. Please note the way we are checking if an app is of container type? Notice : if installer.kind.include? "container". The idea is that we might need to handle installation of different kind of container apps differently. So on amahi.org while adding container apps, for the kind field we have to use something like : container-php5, container-python, container-custom, etc. So to check if an app is container type we have to see if the installer.kind includes "container" pattern inside it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment