--- title: "Create an instance from your own image" description: "Launch a TIR Instance from your own container image, kept in your Container Registry or a public registry such as Docker Hub, and see what the image needs." content_type: "how-to" product: "tir-instance" platform: "TIR" url: "/tir/tir-instance/how-to/create-an-instance-from-your-own-image/" topic: ["create-and-connect"] --- # Create an instance from your own image Run a TIR Instance from your own container image, either from your project's Container Registry or from a public registry such as Docker Hub. An image that already holds your packages starts the same way every time, while packages you install in a running instance are lost each time its container restarts. The task has three parts: build the image, push it to a registry, and launch an instance from it under **Custom Images**. ## Before you begin - Docker on a machine of your own, to build the image. An instance is itself a container with no Docker daemon; to build on TIR instead, use **Save Image** or BuildKit, as [Build the image](#build-the-image) describes. - For a private image, a namespace in your project's **Container Registry**, which is in the side menu under **Storage**. The **Private** tab lists every namespace in the project's **Container Registry** in that region. See [TIR Container Registry](/tir/tir-container-registry/). - An SSH key in your TIR **SSH Keys**. The form asks for a key and a security group that opens port 22 for every custom image, even with **JupyterLab Support** ticked. - Everything a new instance needs, such as credit on a prepaid account. See [Create an instance](/tir/tir-instance/how-to/create-an-instance/#before-you-begin). ## Choose a private or a public image Use a private image, from your project's Container Registry, to launch from an environment you already set up and saved, or to give the instance a framework or configuration beyond what the pre-built images offer. A private image is also the way to give every project member the same environment. Use a public image, such as one from Docker Hub, to launch from an image someone else built: a well-known image, or one a vendor or community maintains. You work in a public image over SSH. ## Make the image ready for TIR TIR starts a custom or public image with its own setup in place of the image's start command, so build the image with that in mind. - Base the image on Ubuntu. TIR's setup installs its tools with `apt-get`. If the image runs as a user other than `root`, give that user passwordless `sudo`. - Build it for `linux/amd64`. TIR checks a public image for that platform when you enter it. - Move anything the image's entrypoint or command used to start into a start script, because TIR's setup runs in place of the entrypoint. - Start background programs from a start script. An instance runs without `systemd`, so `systemctl` does not work. - Keep shell settings, such as an `export PATH=...` line, in the image or in a start script. At every start, `.bashrc` and `.profile` in `/home/jovyan` are replaced with the ones in `/root`, so changes you make to them in a running instance are lost. What happens at start-up depends on what the image is built on: - On a TIR pre-built image, TIR's setup hands over to that image's own start-up, so its app and SSH start as they do on a pre-built image. - On any other image, TIR's setup runs as `root` and sets `HOME` to `/home/jovyan`. It installs `sudo`, `curl`, `git`, `wget`, `vim`, `unzip`, `zip`, a few other basic tools, an SSH server, and an SFTP server. It turns off password login, runs your start scripts as `root`, and starts SSH, and you log in as `root` with your key. After installing its tools, the setup clears the package lists, so run `apt-get update` before you `apt-get install` anything. On those other images, TIR runs your start scripts one after another, waiting for each one to finish, and starts SSH only after the last. Start a program that keeps running in the background, for example with `nohup &`, so that the script returns and SSH can start. An instance from a custom or public image shows **Running** once SSH answers on port 22. JupyterLab runs on a custom image only when it was made with TIR's image builder, or is based on a TIR pre-built image that has JupyterLab. Tick **JupyterLab Support** when you launch such an image from **Private**. You work over SSH in every other custom image and in every public image. ## Build the image Pick the way that suits you: | Way to build | Choose it when | | -------------------------------------------- | ---------------------------------------------------------------------------------------------------- | | A Dockerfile on one of TIR's own base images | You want JupyterLab and SSH to work as on a pre-built image, and a build you can repeat. Start here. | | A Dockerfile on a base image of your own | You already have a base image, and you work in the instance over SSH | | By hand, with `docker commit` | You prefer to install packages interactively and save the result | | **Save Image** on a running instance | You have already set up an instance the way you want it | | BuildKit, on an instance | You have a Dockerfile and want to build it on TIR | The quickest way to a working image is to start from one of TIR's own pre-built images. They already have TIR's start-up, JupyterLab, and SSH, anyone can pull them, and they stay compatible once you add your own packages. - `aimle2e/ubuntu-cuda-jupyter:22.04-12.2.2`: Ubuntu with CUDA and JupyterLab only. - `aimle2e/nvidia-pytorch:23.06-2.1.0`: PyTorch 2.1.0. - `aimle2e/nvidia-tensorflow:23.06-2.12.0`: TensorFlow 2.12.0. - `aimle2e/nvidia-pytorch-transformers:23.06-2.1.0-4.31.0`: PyTorch 2.1.0 with Hugging Face Transformers 4.31.0. Name one of these in your Dockerfile's `FROM` line, add your packages, and build it, tagging it with its full registry path so the next step can push it straight away: ```dockerfile FROM aimle2e/nvidia-pytorch:23.06-2.1.0 RUN pip install --no-cache-dir ``` ```bash docker build --platform linux/amd64 -t registry.e2enetworks.net//: . ``` Replace `` with your Container Registry namespace, `` with the name you want for the image, and `` with its version. You can also start from your own base image. In your Dockerfile, start from your base image with `FROM --platform=linux/amd64` followed by the base image's name, add your packages, and build it for `linux/amd64`: ```bash docker build --platform linux/amd64 -t : . ``` Replace `` with the name you want for the image, and `` with its version, such as `v1`. On an Apple silicon Mac, keep `--platform linux/amd64`. TIR checks the platform only for a public image, when you enter it, so build every image for `linux/amd64`. A Dockerfile is easier to repeat, but you can also build the image by hand: run a container from a base image, install your packages in it, and save the result as a new image. ```bash docker run --platform linux/amd64 -d docker exec -it /bin/bash ``` Install your packages in the container, then leave it, and save your changes as a new image, tagged with its full registry path: ```bash docker commit registry.e2enetworks.net//: ``` Replace `` with your Container Registry namespace, `` with the name you want for the image, and `` with its version. Then log in and push it; see [Push the image to Container Registry](#push-the-image-to-container-registry). To start from an instance you have already set up instead, install your packages on it and save it with **Save Image**. TIR saves the container as an image in a namespace of your Container Registry, ready to launch. See [Save an instance as an image](/tir/tir-instance/how-to/save-an-instance-as-an-image/). To build from a Dockerfile on TIR itself, run BuildKit on an instance; it builds the image and pushes it to your Container Registry in one step. See [Build container images with BuildKit](/tir/tir-instance/how-to/build-container-images-with-buildkit/). ## Push the image to Container Registry In the side menu, under **Storage**, open **Container Registry**, and in your namespace's row select the terminal button under **Commands**. **Docker Commands** gives the three commands to run: - the **Docker Login Command**, which logs in with the namespace's own username and password, a different login from your TIR sign-in - the `docker tag` command, which names the image `//:` - the `docker push` command The registry is `registry.e2enetworks.net` in Delhi and `in-south1-registry.e2enetworks.net` in Chennai. Run the commands on the machine where you built the image. If the push is refused for authentication, log in again with those commands. Once the push finishes, the image is ready to launch. For the registry's side of this step, see [Push an image](/tir/tir-container-registry/how-to/push-an-image/). For a public image, push it to its public registry the way you usually do, and make sure the repository is public, so anyone can pull the image. ## Launch from a private image 1. In TIR, under **Compute**, select **Containers (Instances)**, then **Create Instance**. 2. In **Choose Image**, open **Custom Images**, then **Private**. 3. If you built the image with TIR's image builder or on a TIR pre-built image, tick **JupyterLab Support** so that the instance gets JupyterLab. Leave it clear for any other image. 4. Under **Registry Namespace**, pick your namespace in the project's Container Registry for this region. If there is none yet, follow the field's link to create one. 5. Under **Available Images**, find your image. Use **Search Image** to find it by name, and the refresh button if you pushed it a moment ago. 6. Choose the tag in the image's list, or select the image to use its first tag. You can still change the tag in **Version** at the top of the form. If the namespace is still empty, its **commands** link gives the Docker commands to push an image. Images you saved from another instance are listed here too, the same way. ## Launch from a public image 1. In TIR, under **Compute**, select **Containers (Instances)**, then **Create Instance**. 2. In **Choose Image**, open the **Custom Images** tab, and stay on **Public**. 3. Type the image's name with its tag after a colon, such as `ubuntu:22.04`, `docker.io/library/ubuntu:22.04`, or `pytorch/pytorch:latest`. Include the tag, even for a well-known name such as `pytorch/pytorch`. The name can be up to 128 characters. 4. Wait for TIR to check the image as you type. It checks that the image exists, that it is public, and that it supports `linux/amd64`. When the image passes, the field says **Image is valid**. Otherwise it says what is wrong, such as a missing tag or a private repository. If TIR fails to reach the registry for the check, you can still continue, and the image goes unchecked. 5. Select **Next**. The **Create Instance** form opens for the image. TIR checks a public image again each time the instance starts, and refuses the start if the image fails that check. ## Finish the form and launch The rest of the form works as it does for any instance: name, computing resource, billing, storage, network, and start scripts. See [Create an instance](/tir/tir-instance/how-to/create-an-instance/) for each choice. Two parts matter most for your own image: - Pick at least one SSH key under **SSH Keys**, and a security group that opens port 22 under **Security Group**; the form asks for both for every custom image. If you pick a key and leave the group empty, the form selects the project's default group, which opens port 22. - Under **Startup Script**, pick the start scripts that do what the image's entrypoint used to do. Select **Launch Instance**. The instance shows **Waiting** while the host downloads the image and TIR's setup runs. Each time the instance starts, TIR asks the registry for the image and downloads the parts of it the host is missing. A large image therefore keeps the instance on **Waiting** for longer. If the image or its tag is removed from the registry, the instance stays on **Waiting**. See [Troubleshooting TIR Instances](/tir/tir-instance/troubleshooting/tir-instance/). ## Connect and check your packages Once the instance is **Running**, connect over SSH as `root` with your key, using the command the instance's page shows. See [Connect to an instance over SSH](/tir/tir-instance/how-to/connect-to-an-instance-over-ssh/). If you ticked **JupyterLab Support**, you can open JupyterLab from the instance's **App URL** instead. Run the tools you added to the image to confirm they are there. ## Use Docker images without Docker on the instance An instance is an unprivileged container. You are `root` inside it, but it cannot run the Docker daemon or load kernel modules, so Docker commands that need the daemon do not work there. Use these instead: - To run your own Docker image, build it and push it from another machine, or with BuildKit on an instance, then launch it from **Custom Images**. - To keep packages you add inside an instance, save it as an image; see [Save an instance as an image](/tir/tir-instance/how-to/save-an-instance-as-an-image/). - To run Docker itself, use a [MyAccount GPU node](/myaccount/gpu-node/), a full virtual machine. Its GPU images built on Ubuntu 22.04 come with Docker and the NVIDIA Container Toolkit; on Ubuntu 24.04 you install both yourself. ## Version and update your image Tag your image with a version, such as `v1.2`, instead of relying on `latest`, so you can relaunch the same environment later. Rebuild and push the image again from time to time, to pick up security updates for the packages in it. To add more packages and keep the same image, install them from a start script; see [Run start scripts on an instance](/tir/tir-instance/how-to/run-start-scripts-on-an-instance/).