Files
container/docs/tutorial.md
T
J Logan 94e06e28a0 Refine user documentation. (#24)
- Extract README sections into BUILDING and CONTRIBUTING documents. This
should work better than sections in README as it keeps the README short,
and the BUILDING and CONTRIBUTING files will stand out in the file list.
- Merged localdev document into BUILDING.
- Fixed broken links.
- Changed DNS setup so later DNS-dependent steps should work.
- Added h1 and link to SECURITY document.
2025-06-05 18:50:40 -07:00

315 lines
11 KiB
Markdown

# Tutorial
Take a guided tour of `container` by building, running, and publishing a simple web server image.
## Try out the `container` CLI
Start the application, and try out some basic commands to familiarize yourself with the command line interface (CLI) tool.
### Start the container service
Start the services that `container` uses:
```bash
container system start
```
If you have not installed a Linux kernel yet, the command will prompt you to install one:
```shellsession
% container system start
Verifying apiserver is running...
Installing base container filesystem...
No default kernel configured.
Install the recommended default kernel from [https://github.com/kata-containers/kata-containers/releases/download/3.17.0/kata-static-3.17.0-arm64.tar.xz]? [Y/n]: y
Installing kernel...
```
Then, verify that the application is working by running a command to list all containers:
```bash
container list --all
```
If you haven't created any containers yet, the command outputs an empty list:
```shellsession
% container list --all
ID IMAGE OS ARCH STATE ADDR
%
```
### Get CLI help
You can get help for any `container` CLI command by appending the `--help` option:
```shellsession
% container --help
OVERVIEW: A container platform for macOS
USAGE: container [--debug] <subcommand>
OPTIONS:
--debug Enable debug output [environment: CONTAINER_DEBUG]
--version Show the version.
-h, --help Show help information.
CONTAINER SUBCOMMANDS:
create Create a new container
delete, rm Delete one or more containers
exec Run a new command in a running container
inspect Display information about one or more containers
kill Kill one or more running containers
list, ls List containers
logs Fetch container stdio or boot logs
run Run a container
start Start a container
stop Stop one or more running containers
IMAGE SUBCOMMANDS:
build Build an image from a Dockerfile
images, image, i Manage images
registry, r Manage registry configurations
SYSTEM SUBCOMMANDS:
builder Manage an image builder instance
system, s Manage system components
%
```
### Abbreviations
You can save keystrokes by abbreviating commands and options. For example, abbreviate the `container list` command to `container ls`, and the `--all` option to `-a`:
```shellsession
% container ls -a
ID IMAGE OS ARCH STATE ADDR
%
```
Use the `--help` flag to see which abbreviations exist.
### Set up a local DNS domain (optional)
`container` includes an embedded DNS service that simplifies access to your containerized applications. If you want to configure a local DNS domain named `test` for this tutorial, run:
```bash
sudo container system dns create test
container system dns default set test
```
Enter your administrator password when prompted. The first command requires administrator privileges to create a file containing the domain configuration under the `/etc/resolver` directory, and to tell the macOS DNS resolver to reload its configuration files.
The second command makes `test` the default domain to use when running a container with an unqualified name. For example, if the default domain is `test` and you use `--name my-web-server` to start a container, queries to `my-web-server.test` will respond with that container's IP address.
## Build an image
Set up a `Dockerfile` for a basic Python web server, and use it to build a container image named `web-test`.
### Set up a simple project
Start a terminal, create a directory named `web-test` for the files needed to create the container image:
```bash
mkdir web-test
cd web-test
```
Download an image file for your web server can use:
```bash
curl -L -o logo.jpg https://github.com/apple/container/tree/main/docs/assets/logo.jpg
```
In the `web-test` directory, create a file named `Dockerfile` with this content:
```docker
FROM docker.io/python:slim
WORKDIR /content
COPY logo.jpg ./
RUN echo '<!DOCTYPE html><html><head><title>Hello</title></head><body><p><img src="logo.jpg" style="width: 2rem; height: 2rem;">Hello, world!</p></body></html>' > index.html
CMD ["python3", "-m", "http.server", "80", "--bind", "0.0.0.0"]
```
The `FROM` line instructs the `container` builder to start with a base image containing the latest production version of Python 3.
The `WORKDIR` line creates a directory `/content` in the image, and makes it the current directory.
The `COPY` command copies the image file `logo.jpg` from your build context to the image. See the following section for a description of the build context.
The `RUN` line creates a simple HTML landing page named `/content/index.html`.
The `CMD` line configures the container to run a simple web server in Python on port 80. Since the working directory is `/content`, the web server runs in that directory and delivers the content of the file `/content/index.html` when a user requests the index page URL.
The server binds to the wildcard address `0.0.0.0` to allow connections from the host and other containers. To ensure security, the virtual network used by the containers is not accessible by external systems.
### Build the web server image
Run the `container build` command to create an image with the name `web-test` from your `Dockerfile`:
```bash
container build --tag web-test --file Dockerfile .
```
The last argument `.` tells the builder to use the current directory (`web-test`) as the root of the build context. You can copy files within the build context into your image using the `COPY` command in your Dockerfile.
After the build completes, list the images. You should see both the base image and the image that you built in the results:
```shellsession
% container images list
NAME TAG DIGEST
docker.io/library/python slim 56a11364ffe0fee3bd60af6d...
web-test latest bf91dc9d42f0110d3aac41dd...
%
```
## Run containers
Using your container image, run a web server and try out different ways of interacting with it.
### Start the webserver
Use `container run` to start a container named `my-web-server` that runs your webserver:
```bash
container run --name my-web-server --dns-domain test --detach --rm web-test
```
The `--detach` flag runs the container in the background, so that you can continue running commands in the same terminal. The `--rm` flag causes the container to be removed automatically after it stops.
When you list containers now, `my-web-server` is present, along with the container that `container` started to build your image. Note that its IP address, shown in the `ADDR` column, is `192.168.64.3`:
```shellsession
% container ls
ID IMAGE OS ARCH STATE ADDR
buildkit ghcr.io/apple/container-builder-shim/builder:2.1.1 linux arm64 running 192.168.64.2
my-web-server web-test:latest linux arm64 running 192.168.64.3
%
```
Open the website, using the container's IP address in the URL:
```bash
open http://192.168.64.3
```
If you configured the local domain `test` earlier in the tutorial, you can also open the page the full hostname for the container:
```bash
open http://my-web-server.test
```
### Run other commands in the container
You can run other commands in `my-web-server` by using the `container exec` command. To list the files under the content directory, run an `ls` command:
```shellsession
% container exec my-web-server ls /content
index.html
logo.jpg
%
```
If you want to poke around in the container, run a shell and issue one or more commands:
```shellsession
% container exec --tty --interactive my-web-server bash
root@my-web-server:/content# ls
index.html logo.jpg
root@my-web-server:/content# uname -a
Linux my-web-server 6.1.68 #1 SMP Mon Mar 31 18:27:51 UTC 2025 aarch64 GNU/Linux
root@my-web-server:/content# exit
exit%
```
The `--tty` and `--interactive` flag allow you to interact with the shell from your host terminal. The `--tty` flag tells the shell in the container that its input is a terminal device, and the `--interacive` flag connects what you input in your host terminal to the input of the shell in the container.
You will often see these two options abbreviated and specified together as `-ti` or `-it`.
### Access the web server from another container
Your web server is accessible from other containers as well as from your host. Launch a second container using your `web-test` image, and this time, specify a `curl` command to retrieve the `index.html` content from the first container.
```shellsession
% container run -it --rm web-test curl http://192.168.64.3
<!DOCTYPE html><html><head><title>Hello</title></head><body><p><img src="logo.jpg" style="width: 2rem; height: 2rem;">Hello, world!</p></body></html>
%
```
If you set up the `test` domain earlier, you can achieve the same result with:
```bash
container run -it --rm web-test curl http://my-web-server.test
```
## Run a published image
Push your image to a container registry, publishing it so that you and others can use it.
### Publish the web server image
To publish your image, you need push images to a registry service that stores the image for future use. Typically, you need to authenticate with a registry to push an image. This example assumes that you have an account at a hypothetical registry named `registry.example.com` with username `fido` and a password or token `my-secret`, and that your personal repository name is the same as your username.
To sign into a secure registry with your login credentials, enter your username and password at the prompts after running:
```bash
container registry login registry.example.com
```
Create another name for your image that includes the registry name, your repository name, and the image name, with the tag `latest`:
```bash
container images tag web-test registry.example.com/fido/web-test:latest
```
Then, push the image:
```bash
container images push registry.example.com/fido/web-test:latest
```
### Pull and run your image
To validate your published image, remove your existing web server image, and then run using the remote image:
```bash
container images delete web-test registry.example.com/fido/web-test:latest
container run --name my-web-server --dns-domain test --detach --rm registry.example.com/fido/web-test:latest
```
## Clean up
Stop your container and shut down the application.
### Shut down the web server
Stop your web server container with:
```bash
container stop my-web-server
```
If you list all running and stopped containers, you will see that the `--rm` flag you supplied with the `container run` command caused the container to be removed:
```bash
% container ls --all
ID IMAGE OS ARCH STATE ADDR
buildkit ghcr.io/apple/container-builder-shim/builder:2.1.1 linux arm64 running 192.168.64.2
%
```
To shut down and remove all containers, run:
```bash
container rm --all --force
```
### Stop the container service
When you want to stop `container` completely, run:
```bash
container system stop
```