A small command-line app that translates text between languages. You'll set it up several ways - progressing from a manual install on a cloud VM, to a virtual environment, to a containerized app - which introduces the core tools you'll use throughout AC215.
The goal: run this command-line app on a cloud VM. We do it four ways, each removing a class of fragility from the one before:
- 🛠️ Manual install on the VM. Quick and dirty:
apt,pip, run. Works, but pollutes the system Python and depends on whatever the VM happens to ship with. - ⚡ Same VM, but with
uv. Introduce virtual environments. Dependencies are isolated from the OS and pinned in a lock file, so the next person gets the exact same versions. - 🐳 Docker, on your laptop. Move from "an environment on a machine" to "a portable image." Build, run, and push it to Docker Hub.
- ☁️ Run the Docker image on a VM. Pull what you just pushed and run it on a fresh VM — no source code, no
pip install, noapt. Production-style deploy.
By the end, the same app deploys to any VM with one command.
Complete Tutorial 0 - Setup & Installs first. It covers everything this tutorial assumes: a GCP account + project, VS Code, Git, Docker Desktop, and uv.
You don't need GCP credentials (a service account) for this tutorial - that comes in a later one.
Four short walkthroughs :
- Install on a VM - manually
- Install on a VM - with uv
- Develop with containers (Docker)
- Run on a VM with Docker
Step 1 of 4 — the quick and dirty path. SSH into a fresh VM, install Python + pip directly into the OS, run the app. Works, but everything we install leaks into the system Python — a problem the next step fixes.
- Create a VM Instance from GCP
- SSH into your newly created instance
- Update OS packages:
sudo apt-get update - Install Git:
sudo apt install git
Tip
apt-get vs apt: Both manage Debian packages. apt-get is the older, stable, scriptable interface — predictable output, used in Dockerfiles and CI (we'll cover CI in a later lecture). apt is a friendlier wrapper for interactive use (progress bars, colors). Prefer apt-get in scripts; either is fine on a VM shell like this one.
- Clone App Repo:
git clone https://github.com/dlops-io/simple-translate.git cd simple-translate- Install Python PIP:
sudo apt install python3-pip - Install packages:
pip3 install --break-system-packages googletrans==4.0.0rc1 art
Tip
--break-system-packages: Modern Debian/Ubuntu mark the system Python as "externally managed" (PEP 668), so pip refuses to install into it by default. The --break-system-packages flag overrides that check and installs into the OS Python anyway. We use it here because we haven't introduced virtual environments yet — the next walkthrough fixes this by using uv instead.
- Test out the translations:
python3 cli.pypython3 cli.py -t "Good morning. It is a good morning for cheese." -s "en" -d "es"python3 cli.py -t "Good afternoon. Would you like some cheese?" -s "en" -d "fr"
- Delete your VM when you're done. A running VM keeps charging even when idle. Go to VM instances, select your instance, and click Delete.
Refer to language codes at the bottom of this page.
Step 2 of 4 — same VM, but isolated. We use uv to create a virtual environment so the app's dependencies don't touch the system Python, and uv.lock pins exact versions so the next person gets the same setup.
- Create a VM Instance from GCP
- SSH into your newly created instance
- Update OS packages:
sudo apt-get update - Install Git:
sudo apt install git - Clone App Repo:
git clone https://github.com/dlops-io/simple-translate.git cd simple-translate- Install uv:
curl -LsSf https://astral.sh/uv/install.sh | sh
Tip
Other ways to install uv: If you already have pip on the VM, you can also run pip install uv --break-system-packages (same PEP 668 caveat as before). On macOS locally, brew install uv works. The curl line above is the simplest because it doesn't need anything pre-installed — see Astral's docs for the full list.
- Reload your shell or run:
source $HOME/.local/bin/env - Install python environment from pyproject.toml:
uv sync
Tip
What uv sync does: Three things in one command — (1) reads pyproject.toml (and uv.lock if present) to figure out what packages your project needs, (2) creates a fresh .venv/ in the project directory if it doesn't exist, (3) installs everything into that .venv/ to match the lock file exactly. It's idempotent (safe to re-run) and ~10–100× faster than the classic python -m venv .venv && pip install -r requirements.txt. The next step (source .venv/bin/activate) is what actually puts this venv on your PATH.
- Activate the newly created environment:
source .venv/bin/activate
Tip
What source .venv/bin/activate does: Four things — (1) prepends .venv/bin/ to PATH so python and pip resolve to the venv's binaries, (2) sets VIRTUAL_ENV=/path/to/.venv so tools know which venv is active, (3) changes your shell prompt to show the venv name as a prefix (e.g. (simple-translate) $), and (4) defines a deactivate shell function so you can later run deactivate to undo all three. We use source (not ./activate) because all of this has to happen in the current shell.
- Test out the translations:
python cli.pypython cli.py -t "Good morning. It is a good morning for cheese." -s "en" -d "es"python cli.py -t "Good afternoon. Would you like some cheese?" -s "en" -d "fr"
- Delete your VM when you're done. A running VM keeps charging even when idle. Go to VM instances, select your instance, and click Delete.
Refer to language codes at the bottom of this page.
Step 3 of 4 — package the venv into a portable image. Build a Docker image on your laptop, run it locally, then push it to Docker Hub so any machine with Docker can pull and run it. No more "but it worked on my VM."
You set up Docker Desktop and VS Code in Tutorial 0 (including the
docker run hello-worldcheck). Just make sure Docker Desktop is running before you start.
- Run
docker container ls - Stop any container that is running
- Run
docker system prune - Run
docker image ls
Note
If you cloned earlier on a VM, that doesn't help here — Docker Desktop runs on your laptop, so clone the repo locally:
- Clone or download from here
-
Inside the
simple-translatefolder create a file calledDockerfile -
Follow these steps to create a
Dockerfilestep by step (Do a Build + Run after each step):
Step 1:
We want to base our docker image from python:3.12-slim-bookworm the official Debian-hosted Python 3.12 image
# Use the official Debian-hosted Python image
FROM python:3.12-slim-bookworm
Step 2:
Add Entry point to /bin/bash
ENTRYPOINT ["/bin/bash"]
Step 3: Install uv & copy source code into the container
# Install uv
RUN pip install uv
# Copy the source code
COPY . ./
Step 4: Setup a virtual environment by running uv sync
RUN uv sync
Step 5: Automatically get into the virtual environment shell on startup
# Get into the uv virtual environment shell
CMD ["-c", "source .venv/bin/activate && exec bash"]
Solution Dockerfile:
Dockerfile.txt
- In a terminal make sure you are the location of
simple-translateBuild the docker container by running docker build -t simple-translate -f Dockerfile .
Run the container using:
docker run --rm -ti simple-translateRunning the translate codepython cli.py -t "Good morning" -s "en" -d "es"To exit from container- Type
exitfrom the Docker shell
- Sign up in Docker Hub and create an Access Token
- Login to the Hub:
docker login -u <USER NAME> -p <ACCESS TOKEN> - Tag the Docker Image:
docker tag simple-translate <USER NAME>/simple-translate-ac215 - Push to Docker Hub:
docker push <USER NAME>/simple-translate-ac215
Step 4 of 4 — the production-style deploy. Spin up a fresh VM that has only Docker installed (no Python, no source code), pull the image you pushed in step 3, and run it. This is how real services get deployed.
- Create a VM Instance from GCP
- SSH into your newly created instance Install Docker on the newly created instance by running
sudo apt install docker.io
Check version of installed Docker
sudo docker --version
Run the app using Dockersudo docker run --rm -ti dlops/simple-translate
Run the cli
-
python cli.py -
Delete your VM when you're done. A running VM keeps charging even when idle. Go to VM instances, select your instance, and click Delete.
| No. | Language Name | Native Language Name | Code |
| 1 | Afrikaans | Afrikaans | af |
| 2 | Albanian | Shqip | sq |
| 3 | Arabic | عربي | ar |
| 4 | Armenian | Հայերէն | hy |
| 5 | Azerbaijani | آذربایجان دیلی | az |
| 6 | Basque | Euskara | eu |
| 7 | Belarusian | Беларуская | be |
| 8 | Bulgarian | Български | bg |
| 9 | Catalan | Català | ca |
| 10 | Chinese (Simplified) | 中文简体 | zh-CN |
| 11 | Chinese (Traditional) | 中文繁體 | zh-TW |
| 12 | Croatian | Hrvatski | hr |
| 13 | Czech | Čeština | cs |
| 14 | Danish | Dansk | da |
| 15 | Dutch | Nederlands | nl |
| 16 | English | English | en |
| 17 | Estonian | Eesti keel | et |
| 18 | Filipino | Filipino | tl |
| 19 | Finnish | Suomi | fi |
| 20 | French | Français | fr |
| 21 | Galician | Galego | gl |
| 22 | Georgian | ქართული | ka |
| 23 | German | Deutsch | de |
| 24 | Greek | Ελληνικά | el |
| 25 | Haitian Creole | Kreyòl ayisyen | ht |
| 26 | Hebrew | עברית | iw |
| 27 | Hindi | हिन्दी | hi |
| 28 | Hungarian | Magyar | hu |
| 29 | Icelandic | Íslenska | is |
| 30 | Indonesian | Bahasa Indonesia | id |
| 31 | Irish | Gaeilge | ga |
| 32 | Italian | Italiano | it |
| 33 | Japanese | 日本語 | ja |
| 34 | Korean | 한국어 | ko |
| 35 | Latvian | Latviešu | lv |
| 36 | Lithuanian | Lietuvių kalba | lt |
| 37 | Macedonian | Македонски | mk |
| 38 | Malay | Malay | ms |
| 39 | Maltese | Malti | mt |
| 40 | Norwegian | Norsk | no |
| 41 | Persian | فارسی | fa |
| 42 | Polish | Polski | pl |
| 43 | Portuguese | Português | pt |
| 44 | Romanian | Română | ro |
| 45 | Russian | Русский | ru |
| 46 | Serbian | Српски | sr |
| 47 | Slovak | Slovenčina | sk |
| 48 | Slovenian | Slovensko | sl |
| 49 | Spanish | Español | es |
| 50 | Swahili | Kiswahili | sw |
| 51 | Swedish | Svenska | sv |
| 52 | Thai | ไทย | th |
| 53 | Turkish | Türkçe | tr |
| 54 | Ukrainian | Українська | uk |
| 55 | Urdu | اردو | ur |
| 56 | Vietnamese | Tiếng Việt | vi |
| 57 | Welsh | Cymraeg | cy |
| 58 | Yiddish | ייִדיש | yi |