# Container demo: simple container from scratch This container demo shows how to run a simple web server container. The goal is: - run a webserver written in python3 In order to do so, we will: - create an OCI image using Docker - push that image to a container registry - import it into Unwired Edge Cloud - use it on a device - access the HTTP server from the LAN ## Getting started - if you just want to import and use one of the ready-made demo images, please continue directly to [](import-the-image). - if you would like to build the image yourself, please continue with Step #1 ## Step #1: create your container image Tools used: - Terminal/shell on Linux/Mac - A text editor (e.g. Visual Studio Code) - Docker (install Docker on Linux or use Docker for Mac/Docker Desktop). - Make (install build-essentials on Debian/Ubuntu based Linux distributions; pre-installed on MacOS) - curl (or any other web browser will do) We can create a simple container image using the following Dockerfile. Create an empty directory as your project directory, and within it create a file called ```Dockerfile``` with exactly this content: ```Dockerfile FROM ubuntu:jammy # install system packages RUN apt-get update && apt-get install -y python3 && \ apt-get purge -y unattended-upgrades && \ apt-get autoremove -y && \ rm -rf /var/lib/apt/lists/* # add the files ADD files /opt/www WORKDIR /opt/www # declare port 80 EXPOSE 80 # the command to start the python server CMD ["python3","-m","http.server","80"] ``` Create a new HTML-File by using this shell snippet (Terminal on Linux/Mac) in your project folder created in Step #1: ``` mkdir files echo '
Hello World!' > files/index.html ``` Create a file called ```Makefile``` with this content: ```Makefile # build a local test image build: docker build -t uwcloud/from-scratch:0.1 . # run the image locally run: docker run --rm -it -p 8087:80 uwcloud/from-scratch:0.1 ``` We can perform these steps: - ```make build``` - build the image under the local tag from-scratch:0.1 - ```make run``` - run the image locally As soon as the image is running, please validate the outcome by calling the following command in the local shell. The command is using shell, but you can also open the URL on your local browser: ```shell curl http://localhost:8087/ ``` You should see HTML output like this (or just the ```Hello World!``` text in your browser): ```html Hello World! ``` ### Optional: building for other platforms Please note that in order to use this image on a hardware platform other than your system's host CPU architecture (`amd64` for Intel/AMD CPUs, `arm64` for Apple silicon Macs), you will have to use `docker buildx` in order to build for multiple platforms. This could look like this: ```Makefile # build an image and push it into a registry # - direct pushes are required, since buildx does not access the local docker repository build-all-platforms-and-push: docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t YOUR_TARGET_REPOSITORY/from-scratch:0.1 --push . # run manually before buildx to start up the builder instance. if one is already running, this will error. buildx-init: docker buildx create --use --platform=linux/amd64,linux/arm64,linux/arm/v7 --name multi-platform-builder docker buildx inspect --bootstrap .PHONY: build-all-platforms-and-push buildx-init ``` ## Step #2: push the image to your registry The next step depends on your available infrastructure. If you don't have a registry you can use, there are multiple other options: - create a free account on [Docker Hub](https://hub.docker.com/) to push your image there - use our example image on Docker Hub: [uwcloud/from-scratch:0.1](https://hub.docker.com/r/uwcloud/from-scratch) Of course, you can also customize the image to your likings. (import-the-image)= ## Step #3: import the image Tools used: - [Unwired Edge Cloud Console developer tools](https://admin.wifi.unwired.at/developer/playground) This step: - imports the OCI image - defines the node service - versions increase automatically (if the version parameter is not passed in ```node_service_input``` - LAN network: dhcp server with auto generated range - WAN network: allocated IP address - amd64 hardware platform - no file or directory mounts or persistent volumes - a memory limit of 50 MB In order to perform the import to your customer account, you will need to replace the customer ID in the mutation below. You can find the customer URL by opening device management (DM) in the [Unwired Edge Cloud Console](https://admin.wifi.unwired.at/) and taking the first long UUID from the URL. E.g. for an URL like: ```https://admin.wifi.unwired.at/device-management/01234567-0000-1111-2222-012345678901/``` the resulting customer ID would be: ```01234567-0000-1111-2222-012345678901``` In order to import this image in the [Unwired Edge Cloud Console Developer Tools](https://admin.wifi.unwired.at/developer/playground), the following GraphQL mutation will work. This example uses the Unwired provided public image and please feel free to use it too. ```{hint} Using your own image: Please make sure to customize the image URL to your image URL and only import platforms that exist in your image repository. Authentication parameters can be specified using the ```authn``` parameter for each image source. See below for details. ``` ```graphql mutation import_container_from_scratch { DM_import_node_service( input: { customer_id: "TODO: insert your customer ID here" node_service_input: { container_image: "from-scratch" name: "from-scratch" apikey_roles: [] wipe_on_update: false access_gpsd_enabled: false network_config: { lan_configure_network: dhcp access_interfaces: { name: "eth1" label: "lan" } access_provided_subnet: "10.140.0.1/16" dhcp_range_template: "10.140.0.1/24" dhcp_lease_time_seconds: 600 wan_configure_network: allocated wan_dns_override: [] masq: true } } image_sources: [ { arch: amd64 image_reference: "uwcloud/from-scratch:0.1" } { arch: armhf image_reference: "uwcloud/from-scratch:0.1" } { arch: arm64 image_reference: "uwcloud/from-scratch:0.1" } ] metadata: { memory_limit_mb: 50 } } ) } ``` This mutation will return a result with a job ID per imported image platform. You can simply copy & paste the job IDs into the next query. ### Checking job status This query allows you to check the job status with the job IDs received from the import mutation. ```graphql query job_status { DM_get_node_service_import_jobs(ids: ["job ID 1", "job ID 2", "job ID 3"]) { node_service_import_job_id node_service_id state logs created last_modified arch } } ``` The output will show the state (in_progress, ok, failed) and a log of what happened after the import job is done. ### Delete node_service of failed Import Job This mutation allows you to delete a node_service from a (failed) import job. Please make sure to replace the `