Working with Containers

In this section you'll learn a variety of methods for managing and building containers and images with Turbo Studio and the command-line interface. You'll also learn how to integrate containerization with your continuous integration server.

Working with Containers

Creating Containers

The turbo new command starts new containers. You must specify a base image to provide the virtual filesystem and registry for the container. If no files or registry keys are necessary, use the empty clean image.

# Launch a command window in a new container with clean as the base image
> turbo new clean

Operations executed in the new command window are applied to the container, not the host system. This means you do not have access to local files, the container is fully isolated.

To avoid confusion, the prompt is prepended by the image name and the first 8 characters of the container ID when a command window is running in a container. Alternatively, a container can be assigned a name, this will be illustrated in the Installing MSI Packages in Containers section.

# Host command window
> turbo new clean

# Container command window
(clean#0bad25c4) >

Edit and modify the container's virtual filesystem and registry using the same command-line interfaces available in Windows Command Prompt.

Installing MSI Packages

Installing MSI packages in containers is supported, but in some instances an install may fail e.g. a custom action may attempt to runs but fails when run in the fully isolated Turbo VM. If an MSI install fails, try creating the container using Turbo Studio.

This section will detail steps for creating a container for InstEd, a popular MSI editor.

Begin by downloading the application here

Copy the MSI to a new directory: C:\Installers on your local machine.

By design the Turbo VM is fully isolated and does not permit access to local files. In order to use the MSI in your local C:\Installers directory, you must poke a hole in the isolation. Use the --mount flag to poke a hole in the isolation. Use the -n flag to set a name for the container.

# Poke a hole in isolation
> turbo new clean --mount="C:\Installers" -n=instedcont

Launch the install.

# Install InstEd
(instedcont#95c15a32) > C:\Installers\InstEd-1.5.15.26.msi

When prompted, click Next.

Click on the checkbox to agree to accept the terms in the license agreement and then click Next.

Click Next.

Click Install.

Click Finish.

Exit the Turbo VM from the launched command prompt.

# Close Turbo VM
(instedcont#95c15a32) > exit

Once you finish editing a container, it can be saved and distributed in the form of images. For more information on images, read on here.

Ensure the --startup-file flag is set to the application's main executable. Provide an image name, in this example use instedit.

# Commit container into an image
> turbo commit instedcont --startup-file="C:\Program Files (x86)\instedit.com\InstEd\InstEd.exe" instedit

By default, the commit command merges sandbox changes with the base images and builds a new image from these merged layers. Specifying the "--no-base" option builds a new image of the sandbox changes without merging the base images.

Test the new InstEd image.

# Launch a new instance of Insted using the instedit image
> turbo new instedit

Accessing Local Files

You may notice when attempting to open an MSI on your local machine, you will not have access to it. Similarly, when creating a new MSI and attempting to save to a local machine directory, you will not be able to save locally. This is expected behavior. By default containers run in full isolation. Use the --isolate flag to launch a new instance of InstEd with isolation set to merge with the local system.

Launch application with access to local files.

# Launch instedit image
> turbo new instedit --isolate=merge

You will now have access to any local files.

Pushing Images to the Hub

We created an image which can be pushed to our Hub and run by anybody. To do this, we must first login to Turbo.net from the command prompt. Enter turbo login and then enter your turbo username and password when prompted.

# Login
> turbo login

Push the image by entering turbo push .

# Login
> turbo push instedit

Publishing Images

Our image has been pushed to the Hub. Now we will configure the repo settings and other publishing settings. Navigate to Turbo.net and clicking Sign In.

If you do not have a Turbo.net account click Sign Up to create a new account. If you do have a Turbo.net account, enter your Turbo.net username and password and then click Sign In.

After logging into Turbo.net you are presented with your home screen that contains your applications. Click on instedit.

Hover over the large icon in the header of the page to upload a suitable image for the application. Hover just below the instedit text in the banner and click edit to provide a description.

On the same page, hover beside the description heading and click edit to provide a description of the application. When complete, hover over the readme heading and click edit to provide information useful to people who may try to use your image. e.g. what commands should be used.

Navigate to Settings. A default display name is set, you can change this to something more appropriate such as Instedit or Insted.

Optionally, under Repo Information enter a build script URL if you have one. For more information on how to create a build script read on here. Enter a Developer website and Support website if desired. This information will be displayed on the application's repo page. When using a free account, click Update as there will be no other options available for you.

The Turbo.net Hub provides the ability to create custom run pages for applications. For an example of this, click here. The run page provides a great presentation and end user experience. If enabled, this run page can also be embedded within a website or blog. For an example of an embedded run page click here and scroll to the bottom of the page.

Enter a Heading, which will be the application name displayed to the end users. Enter a SubHeading which should contain a brief description of the application. Optionally enter an Article URL which will provide a hyperlink to a source page e.g. if you choose to host an application you created, you can link to your own hosted blog with information about the application.

Click on Choose File to upload a Splash image. (1033 x 752 px is a good size for this) This could be a static screenshot of the application or possibly an animated gif of the application being used. Click on Choose File to upload a Background image. Optionally repated these steps to upload a Splash thumbnail and Background thumbnail image.

Optionally, enter a Run button color and Background image color. This may be useful if the background you choose conflicts with the color of the button.

If you do not wish to use a Splash image you may choose to enable a Background banner. This will present a banner across the run page containing your run page information.

Navigate to Icon Settings and set a Background color. If the icon you uploaded has a white background, it is best to enter transparent as the value for the Background color. Optionally select if the icon should Padded. This will trim the edges of the image. In some cases, this can make certain icons look much better.

Navigate to Launch Configuration. If any additional flags are required for the application to function, enter these here. For a list of available flags read here. Enter additional Image layers if you wish to launch the application with other dependent images. Always ensure the application you wish to launch is in the last image in the list. Seperate each image you wish to layer with a comma.

To force the use of a certain version of the Turbo VM enter the version number under Stable VM version.

In the above example, InstEd requires local file access. This can be permitted by setting File Isolation to Write Copy of Merge.

Enable Isolate network to isolate all tcp,udp and named object calls within the container.

Navigate to Admin Settings. Under Shortcut Icon (.ico) click Choose File to upload an icon file for the application. Click on the dropdown menu for Categories to assign the relevant categories for the application to appear in on the Turbo.net Hub.

Enable the application as Official to ensure it can be found in Turbo Launcher and from a search on the Turbo.net Hub. Click Embeddable to allow the run page to be embedded on websites and blogs.

When complete. Click Update.

We are always looking for new applications to host on the Turbo.net Hub. If you would like to share your work with everybody, please reach out to us via Twitter: @turbohq or alternatively send us an e-mail to: support@turbo.net.

Managing Containers

Once created, track and manage containers with these commands.

# List containers with base images, commands, creation date, and status
> turbo containers

ID           Images            Command       Created          Status
03bddd8bef   spoonbrew/clean   cmd           8/14/2014 1:03   Stopped
52hd888xa3   local/server-app  startup.bat   8/14/2014 1:00   Running

# Remove a specific container from the host system
> turbo rm 03bddd8bef

# Remove all containers
> turbo rm -a

Note that running containers must be stopped before being removed.

Processes and Stopping Containers

The life cycle of a container is controlled by the processes within that container. Processes in a container spawn as child processes of the Turbo VM executable, which manages the container environment.

When a process within a container exits or completes, the container exits as well.

# You can forcefully exit a container from the native command window
> turbo stop <container id>

This command kills the Turbo VM managing process along with any child processes.

You can also explicitly shut down a container from a command window running in the container by typing exit or entering Ctrl+C.

# If necessary, restart a closed container and specify the container ID
> turbo start 8dpp9eb5

Debugging

If you experience crashing or other issues with Turbo containers, here are several commands to help you debug and fix these problems.

# If your container unexpectedly crashes, enable diagnostic mode
> turbo run --diagnostic <image>

# Then fetch the logs created by the run
> turbo logs

This command returns logs of all the standard streams (STDIN, STDOUT, STDERR) for the specified container.

Please note that enabling diagnostic mode will cause your container to run slower than expected. Therefore we recommend only enabling this mode for diagnostic/debugging purposes.

# You can also debug by viewing changes to a container's filesystem and registry
> turbo diff 8dpp9eb5

# Similarly you can revert changes to get the container back to a running state or to debug changes
> turbo revert 8dpp9eb5

IP Routing

Turbo container IP routing can be used to map container network ports to those on the native machine. This is possible using the --route-add flag.

The syntax for the --route-add flag is ://:. For example, to map container TCP port 8080 to host port 80, you would use the command flag --route-add=tcp://8080:80.

In addition, the ip protocol is supported which applies routing to all IP-based communication. For example, the command --route-block=ip blocks all IP traffic. Subsequent --route-add flags can be appended to whitelist specific IP addresses.

It is also possible to map a container port to a random high host port for security purposes or to avoid binding conflicts. This port can subsequently be queried with the turbo netstat command. To map container TCP port 4321 to a high random host port, use the flag --route-add=tcp://4321:0. The 0 here represents a randomly assigned high port.

Sample: PuTTY Whitelisting

PuTTY is a popular free Telnet client for Windows. To create a PuTTY container with all outbound access blocked except to IP address 10.0.0.34:

> turbo new putty --route-block=ip --route-add=ip://10.0.0.34

Now let’s reroute all traffic from 1.1.1.1 to 10.0.0.34, making it possible to connect to host at 10.0.0.34 typing address 1.1.1.1 in PuTTY:

> turbo new putty --route-block=ip --route-add=ip://10.0.0.34 --route-add=ip://1.1.1.1:10.0.0.34

It is also possible to block or map IP ranges using the CIDR notation. For example, the following command allows PuTTY in the container to connect only to hosts in the 192.168.1.0/24 network:

> turbo new putty --route-block=ip --route-add=ip://192.168.1.0/24

To disallow connection to a set of specific set of IP addresses or ranges (“blacklisting”), simply specify them in the --route-block parameter:

> turbo new putty --route-block=ip://10.0.0.34

The --route-add and --route-block command flags are also supported within the commit command, so it is easy to save custom network stacks into deployable images.

Host Name-based IP Restrictions

This syntax also allows specifying host names instead of IP addresses. Often using a human-readable domain name is easier to setup, more readable, and is automatically maintained across IP address changes. When a host name is specified, it is treated as if its IP address had been specified. Cases where multiple IP addresses are resolved — including IPv6 — are handled properly. Note however that you cannot specify a host name on the right side of a route-add mapping since the result would be ambiguous if the host name resolved to multiple IP addresses.

For example, to run a Chrome container allowing only access to the turbo.net and blog.turbo.net domains, you can use the command:

> turbo new --route-block=ip --route-add=ip://turbo.net --route-add=ip://blog.turbo.net chrome https://turbo.net

Wildcards are supported in host name routing. For example, to unblock turbo.net and all of its subdomains, use the command:

> turbo new --route-block=ip --route-add=ip://*.turbo.net chrome https://blog.turbo.net

Taking this a step further, to run a Chrome container disallowing access to the facebook.com domain and all of its subdomains:

> turbo new --route-block=ip://*.facebook.com chrome

Creating IP Routing Layers

If you need to apply the same set of IP routing rules across multiple applications, it is inconvenient to repeat them each time you create a container. In this situation, you can create a layer containing the appropriate IP routing rules and apply it to all of the applicable containers.

For example, to create a layer that blocks access to all IP addresses except the turbo.net domain, the network 192.168.1.0/24, and 127.0.0.1, first create a container with the rules:

> turbo new --name=network-blocking-container --route-block=ip --route-add=ip://turbo.net --route-add=ip://192.168.1.0/24 --route-add=ip://127.0.0.1

We then commit the routing container to a new image called network-blocking-layer:

> turbo commit network-blocking-container network-blocking-layer

We can now use this layer together with any image:

> turbo new network-blocking-layer,firefox https://turbo.net
> turbo new network-blocking-layer,putty -ssh 192.168.1.1

These applications can in turn be committed to a new image that is ready for deployment:

> turbo commit firefox firefox-restricted
> turbo run firefox-restricted

IPv6 Routing

IPv6 address are also supported by this network syntax. The colons in IPv6 addresses causes conflicts with this syntax however. To solve this, IPv6 addresses in Turbo commands are enclosed in square brackets.

For example, to block the localhost address, use the command:

> turbo new putty --route-block=ip://[::1]

To block all IP traffic except the link local IPv6 space. Notice we can use the CIDR notation to specify a range of addresses.

> turbo new putty --route-block=ip --route-add=ip://[fe80::c218:85ff:febd:5c01/64]

To redirect traffic from a specific IPv6 address to localhost:

> turbo new putty --route-block=ip --route-add=ip://[2001:cdba::3257:9652]:[::1]

Routing Files

While working with long routing lists (eg to block advertising or other undesired sites) it is inconvenient to add many --route-block and --route-add flags to command line or TurboScript file. To simplify this, we use the --route-file flag.

The routing file has a simple INI-style syntax:

[<protocol-action>]
Host-address

The header contains the definition for how the below addresses should be interpreted. Supported protocols are ip, tcp, and udp and supported actions are add and block.

To block/unblock all IP addresses we can use the 0.0.0.0 literal or *.

For example, a routing file that blocks all IP traffic except turbo.net/spoon.net addresses:

[ip-block]
*
[ip-add]
*.turbo.net
*.spoon.net

The route file can be used with all other container management commands. For example:

> turbo try firefox --route-file=routes.txt --name=turbo-firefox

It can also be used during commit to persist routing settings into an image:

> turbo new firefox --name=fx
> turbo commit fx turbo-firefox –route-file=routes.txt

And can be included in a TurboScript build command:

> turbo build turbo.me --route-file=routes.txt

Blocked Site Routing

IP routing can also be used to reroute traffic from blocked sites to an internal network. As an example, we will reroute all traffic from nytimes.com to an internal containerized web server.

First, we run a preconfigured Apache server that binds to local port 80:

> turbo new apache/apache-samples --detach

Next, we run firefox with routing enabled:

# route nytimes.com traffic to local web server
turbo new firefox --route-add=ip://*.nytimes.com:127.0.0.1 

After typing nytimes.com in browser it shows our custom page, instead of original site:

Sample: Creating Single Site Browsers

Turbo’s IP routing capabilities can be used to create custom browsers that allow access only to a specific site or set of sites. A simple solution was shown in previous articles, eg:

> turbo new firefox --route-block=ip --route-add=ip://*.turbo.com --route-add=ip://*.spoon.com

The above command works for simpler websites, but more advanced websites use resources from multiple external sources. We need to allow access to those external sites for the site to load properly.

To simplify the process of creating a routing file for this scenario, we have published a PowerShell script to help. In this example we will show how to obtain this script and use it to create a forbes.com limited browser.

First, download the script from turboapps repository: route-file-builder.ps1

Example script usage:

PS> Route-file-builder.ps1 -urls “http://turbo.net”

PS> Route-file-builder.ps1 -urls (“http://turbo.net”, “http://spoon.net”) -routeFile c:\path\to\routes.txt

When the -routeFile flag is not passed, output is printed to the console.

The script runs the container in the background with a fully blocked network and iteratively unblocks hosts that the website tries to connect to.

Let’s run it for forbes.com:

PS > .\route-file-builder.ps1 -urls forbes.com -routeFile c:\s\forbes-routes.txt
Security warning
Run only scripts that you trust. While scripts from the Internet can be useful,
this script can potentially harm your computer. If you trust this script, use
the Unblock-File cmdlet to allow the script to run without this warning
message. Do you want to run C:\s\route-file-builder.ps1?
[D] Do not run [R] Run once [S] Suspend [?] Help (default is "D"): R
Running browser...
Did everything work correctly? (y/n):

In every iteration, the script opens firefox to the forbes.com site. After closing the browser it asks the user if the site was displayed correctly. Repeat the process until the web page displays correctly.

In the first iteration firefox is not displaying anything, so we choose n

Running browser...
Did everything work correctly? (y/n): n
Running browser...
Did everything work correctly? (y/n): n
Running browser…
Did everything work correctly? (y/n): y

After the fourth iteration the site is displayed correctly. Now we answer yes and script ends.

Now we can open the forbes-routes.txt file and check all the unblocked hosts:

[ip-add]
*.forbes.com
127.0.0.1
tiles.r53-2.services.mozilla.com
tiles.services.mozilla.com
location.services.mozilla.com
i.forbesimg.com
a1586.g1.akamai.net
self-repair.mozilla.org
shavar.services.mozilla.com
shavar.prod.mozaws.net
aus5.mozilla.org
aus5.external.zlb.scl3.mozilla.com
safebrowsing.google.com
sb.l.google.com
services.addons.mozilla.org
olympia.prod.mozaws.net
versioncheck-bg.addons.mozilla.org
blocklist.addons.mozilla.org
ocsp.digicert.com
search.services.mozilla.com
tiles-cloudfront.cdn.mozilla.net
www.googletagmanager.com
b.scorecardresearch.com
stats.g.doubleclick.net
tags.bluekai.com
consent.truste.com
contextual.media.net
rt.liftdna.com
www.googletagservices.com
cs9.wac.phicdn.net
tracking-protection.cdn.mozilla.net
connect.facebook.net
content.dl-rms.com
h.nexac.com
forbescount.xmlshop.biz
a1.vdna-assets.com
ml314.com
load.amexp.exelator.com
ox-d.forbesbidder.servedbyopenx.com
partnerad.l.doubleclick.net
us-ads.openx.net
ib.adnxs.com
ssum.casalemedia.com
medianet-d.openx.net
qsearch.media.net
[ip-block]
0.0.0.0

As an additional step, it is possible to manually cleanup the list (eg remove the Mozilla sites) and prepare a minimal working configuration.

The routing data can later be committed into a new image with turbo commit --route-file command.

Tips

Running Containers as Different Domain Users

By default Turbo containers will run in the security context of the user executing the turbo command. But what if we need to run as a different user?

In this example, let's run SQL Server Management Studio as a different domain user than the currently logged in user. In our scenario we have the Turbo.net Client installed in the local profile (the default behavior).

Our first attempt is to just use the runas command to execute the command turbo run ssms2012:

> runas /user:user@domain "turbo run ssms2012"
Enter the password for user@domain:
Attempting to start turbo run ssms2012 as user "user@doamin" ...
RUNAS ERROR: Unable to run - turbo run ssms2012
5: Access is denied.

Unfortunately with the Turbo.net Client installed in the local profile I cannot use runas to run SSMS in the user context I want since it does not have access to that user's profile.

One workaround then is to install the Turbo.net Client for all users and then use runas:

# install the client for all users
> turbo-client.exe --all-users

# run as a different user
> runas /user:user@domain "turbo run ssms2012"

This works well but we may not want to reinstall the plugin or may not want to install it for all users.

We can solve this by using runas with the /netonly flag:

> runas /netonly /user:user@domain "turbo run ssms2012"

The /netonly flag forces the application to use the runas account for remote resources and the logged in account for local resources.

Questions? Projects? Talk to us.