# 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 ## Step #1: create your container image We can create a simple container image using this Dockerfile: ```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"] ``` Creating a new HTML-File: ``` mkdir files echo 'Hello World!' > files/index.html ``` Using this Makefile: ```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``` - locally run the image As soon as the image is running, please validate by calling the following command in the local shell. The command: ```shell curl localhost:8087 ``` You should see HTML output like this: ```html Hello World! ``` ## 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 options: - create a free account on [dockerhub](https://hub.docker.com/) to push your image there - use our image on dockerhub: [uwcloud/from-scratch:0.1](https://hub.docker.com/r/uwcloud/from-scratch) Of course you can also customize the image to your likings. ## Step #3: import the image 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 Please note that in order to use this image on a hardware platform other than amd64 you will have to use docker buildx in order to build it 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 ``` In order to import this image in the [Unwired Edge Cloud Console dev tools](https://admin.wifi.unwired.at/developer/playground) the following GraphQL mutation will work. Please make sure to customize the image URL to your image URL and also only import platforms that exist in your image repository: ``` mutation import_container_from_scratch { DM_import_node_service( input: { customer_id: "102e88a2-86cf-4a2d-8712-99e8e652db48" 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 } } ) } ``` ### Checking job status This query allows you to check the job status with the job IDs received from the import mutation. ``` query job_status { DM_get_node_service_import_jobs(ids: ["44f68578-1234-49dd-8c12-ccdd275ef123", "ef895fb3-1235-491e-a711-2cb3ac165124", "4393a8d0-1236-4d37-a9e2-edc2b4c1a125"]) { 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 `` with the node_service_id received from `DM_get_node_service_import_jobs` query. ```grqphql mutation del_job { DM_del_node_service(id: "") } ``` ## Step #4: use it on a device When configuring a device you can now add the fully built container to the device configuration. Steps: - create a client network uplink (e.g. CloudLink or NAT) - click the + sign left of the client network uplink to add a container - select your container - attach a client network to it (best a LAN network with either ethernet untagged or wireless LAN) ## Step #5: access it from the LAN network Your device should be networked like this: LAN -> Router (with container) -> WAN Then when you connect your computer or VM to the LAN network you should: - get an IP address over DHCP - be able to access the sample web page with the browser on: [http://10.140.0.1/](http://10.140.0.1/) ## Advanced topics to follow up with ### Running multiple services in a container The following list is a set of recommendations: - supervisord and other light weight process monitoring systems work very well to run multiple processes in a single container. - systemd is not very well suited to run multiple processes in containers, at minimum it is recommended to disable any kind of background job that modifies the disk. This includes but is not limited to: - systemctl disable apt-daily.timer apt-daily.service apt-daily-upgrade.timer e2scrub_all.timer e2scrub_all.service motd-news.timer motd-news.service - the [official recommendation by docker to run multi-service containers](https://docs.docker.com/config/containers/multi-service_container/) ### Network configuration Please see the [container intro about network configurations](../container/container_intro.md#network-configurations) ### Environment variables Please see the [container intro about environment](../container/container_intro.md#lxc-env-for-environment-variables) ### Time good status Please see the [container intro about time good](../container/container_intro.md#time-good-status)