Skip to content

Commit

Permalink
Cleanup user-guide pages mu-t
Browse files Browse the repository at this point in the history
The last pages of the User Guide requiring cleanup have been addressed.
Simplified language and rst, style fixes.

QA Steps: Did not step through all instructions. Rendered HTML was
inspected visually. Ran linter and linkcheck.

This commit applies to FFTK 988

Signed-off-by: Katrina Prosise <katrina.prosise@foundries.io>
  • Loading branch information
kprosise committed Aug 17, 2023
1 parent 9d318ee commit ce0fa3b
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 192 deletions.
Binary file removed source/_static/userguide/submodule/newrepo.png
Binary file not shown.
139 changes: 47 additions & 92 deletions source/user-guide/multi-stage-container/multi-stage-container.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,29 @@
Multi-Stage Container Builds
============================

When developing for embedded devices, optimization is one of the most
important things to consider.
Optimization is always a consideration when developing for embedded devices.
Using Multi-stage builds optimize your Dockerfiles, and keep them easier to read and maintain.

Multi-stage builds are useful to optimize your Dockerfiles and keep them
easy to read and maintain.

You can find more information about it on: `Use multi-stage builds`_.
.. seealso::
Docker's documentation on `multi-stage builds`_.

This guide assumes you have Docker installed on your computer.

To summarize, multi-stage container builds allow you to develop in one stage and
copy just the necessary artifacts to the next stage. That being said, in the first
stage you can install dependencies for development, like a toolchain, and compile
your application. In the final stage, you can keep the image nice and clean with
just what is necessary for your application while making use of the final artifacts from
the first stage.
To summarize, multi-stage container builds allow you to develop in one stage, then copy only the necessary artifacts to the next stage.
In the first stage you can install dependencies for development, like a toolchain, and compile your application.
In the final stage, the image is kept clean with just the necessities for your application.
This is done by making use of the final artifacts from the first stage.

This guide presenst a Dockerfile implementing a ``helloworld`` application written in C.

This section will present a Dockerfile implementing a ``helloworld`` application
written in C.
In the first example, the Dockerfile is implementing everything in a single stage, leaving all objects and spare software in the image.

In the first example, the Dockerfile is implementing everything
in a single stage, leaving all the objects and spare software in the image. The
second example shows how to convert it into a multi-stage container, where the
build happens in the first stage, and all the objects and spare software
stay in the first stage. Finally, the second stage copies the binary from the
first stage and ends up with a smaller and optimized image.
The second example shows how to convert this into a multi-stage container.
This time, the build happens in the first stage, and the second stage copies the binary—ending with a smaller and optimized image.

Both examples, single and multi-stage, will use the same file structure:
Both examples use the same file structure:

.. prompt:: text
::

├── single
│   └── Dockerfile
Expand All @@ -51,31 +44,19 @@ Create the file structure:

Create the ``helloworld.c`` file:

.. prompt:: bash host:~$, auto

host:~$ gedit helloworld.c

**helloworld.c**:

.. prompt:: text
.. code-block:: c
#include <stdio.h>
int main()
{
printf("hello, world!\n");
}
/* helloworld.c */
/* helloworld.c \*/
Create the ``start.sh`` file:

.. prompt:: bash host:~$, auto

host:~$ gedit start.sh

**start.sh**:

.. prompt:: text
.. code-block:: bash
#!/bin/sh
Expand All @@ -96,13 +77,9 @@ Single Stage Container

Create the ``Dockerfile`` that implements the single stage container:

.. prompt:: bash host:~$, auto

host:~$ gedit single/Dockerfile
``single/Dockerfile``:

**single/Dockerfile**:

.. prompt:: text
.. code-block:: dockerfile
FROM debian:bullseye-slim
RUN echo "-------Single-Stage--------------"
Expand All @@ -123,20 +100,18 @@ Create the ``Dockerfile`` that implements the single stage container:
ENTRYPOINT ["/app/start.sh"]
The ``Dockerfile`` is very simple. It installs ``build-essential``,
copies the files ``helloworld.c`` and ``start.sh`` to the container image,
compiles ``helloworld.c`` and sets the entrypoint to start the ``start.sh`` script.
The ``Dockerfile`` is straightforward..
It installs ``build-essential``, copies the files ``helloworld.c`` and ``start.sh`` to the container image,
then compiles ``helloworld.c`` and sets the entrypoint to start the ``start.sh`` script.

Build the docker example and check the image size:
Build the Docker example and check the image size:

.. prompt:: bash host:~$, auto

host:~$ docker build --tag single:1.0 -f single/Dockerfile .
host:~$ docker image ls

**Example Output**:

.. prompt:: text
::

docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
Expand All @@ -148,9 +123,7 @@ Run the image and open a second terminal:

host:~$ docker run -it --rm --name single single:1.0

**Example Output**:

.. prompt:: text
::

hello, world!
hello, world!
Expand All @@ -162,36 +135,28 @@ In the second terminal, inspect the image and note that the spare files are pres

host:~$ docker exec -it single ls /app

**Example Output**:

.. prompt:: text
::

helloworld helloworld.c start.sh

Note that the gcc software is present in the image:
Note that the GCC compiler is present in the image:

.. prompt:: bash host:~$, auto

host:~$ docker exec -it single sh -c 'type gcc'

**Example Output**:

.. prompt:: text
::

gcc is /usr/bin/gcc

Multi-Stage Container
---------------------

Create the ``Dockerfile`` that implements the multi-stage container:

.. prompt:: bash host:~$, auto

host:~$ gedit multi/Dockerfile
Create the ``Dockerfile`` to implement the multi-stage container:

**multi/Dockerfile**:
``multi/Dockerfile``:

.. prompt:: text
.. code-block:: dockerfile
FROM debian:bullseye-slim AS builder
RUN echo "-------Multi-Stage--------------"
Expand Down Expand Up @@ -226,70 +191,60 @@ Create the ``Dockerfile`` that implements the multi-stage container:
ENTRYPOINT ["/app/start.sh"]
In this case, the ``Dockerfile`` is divided into two stages: ``builder`` and ``final-stage``.
The first stage starts with ``AS builder`` after specifying the starting image (first line of the Dockerfile). Next,
it installs ``build-essential`` and compiles ``helloworld.c``.
This ``Dockerfile`` is divided into two stages: ``builder`` and ``final-stage``.
The first stage starts with ``AS builder`` after specifying the starting image (first line of the Dockerfile).
Next, it installs ``build-essential`` and compiles ``helloworld.c``.

The second stage starts with ``AS final-stage`` right after specifying the image used
for the second stage (line 18 of the Dockerfile).
Finally, it ``COPY`` the ``helloworld`` binary from the first stage using the parameter ``--from=builder``.
The second stage starts with ``AS final-stage`` after specifying the image to be used. (line 18 of the Dockerfile).
Finally, ``COPY`` get the ``helloworld`` binary from the first stage using the parameter ``--from=builder``.

Build the docker example and check the image size:
Build the Docker example and check the image size:

.. prompt:: bash host:~$, auto

host:~$ docker build --tag multi:1.0 -f multi/Dockerfile .
host:~$ docker image ls

**Example Output**:

.. prompt:: text
::

docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
single 1.0 ba94763b6fe4 25 seconds ago 351MB
multi 1.0 bdeac19070ea 50 minutes ago 80.4MB

Note the difference between the `single` and `multi` images. A simple ``helloworld``
with just the ``build-essential`` software shows how useful a multi-stage container could be.
Note the difference between the `single` and `multi` images.

Run the image and open a second terminal:

.. prompt:: bash host:~$, auto

host:~$ docker run -it --rm --name multi multi:1.0

**Example Output**:

.. prompt:: text
::

hello, world!
hello, world!
hello, world!

In the second terminal, inspect the image and note that only the needed files are
present in the image (``helloworld.c`` is not installed in the final stage):
In the second terminal, inspect the image.
Note that only the needed files are present in the image (``helloworld.c`` is not installed in the final stage):

.. prompt:: bash host:~$, auto

host:~$ docker exec -it multi ls /app

**Example Output**:

.. prompt:: text
::

helloworld start.sh

Note that the ``gcc`` software is not installed in the final stage:
Notice how ``gcc`` is not installed in the final stage:

.. prompt:: bash host:~$, auto

host:~$ docker exec -it multi sh -c 'type gcc'

**Example Output**:

.. prompt:: text
::

gcc: not found

.. _Use multi-stage builds: https://docs.docker.com/build/building/multi-stage/
.. _multi-stage builds: https://docs.docker.com/build/building/multi-stage/
19 changes: 11 additions & 8 deletions source/user-guide/offline-update/offline-update.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,20 @@ Prerequisites

1. Enable Offline Update support, i.e. add ``aklite-offline`` to ``PACKAGECONFIG`` of ``aktualizr``. For example:

.. prompt:: text
.. prompt:: bash

cat meta-subscriber-overrides.git/recipes-sota/aktualizr/aktualizr_%.bbappend
PACKAGECONFIG:append = " aklite-offline"
2. Enable :ref:`ug-container-preloading` if you would like to update ``Compose Apps`` along with rootfs (aka ostree).

3. Ensure that :ref:`TUF keys are taken offline <ref-offline-keys>`. If they are not, then do it.
3. Ensure that :ref:`TUF keys are taken offline <ref-offline-keys>`.

4. Build an LmP image and flash it onto a target device or update the device with the image via OTA.


Obtaining Offline Update Content
--------------------------------
Once the prerequisites are met, download the offline update content from the FoundriesFactory to some medium, e.g., a USB drive, which can be attached to a target device.

First download the offline update content from your Factory to an install medium which can be attached to the target device.
The offline update content consists of:

1. `TUF metadata`_;
Expand All @@ -51,6 +51,7 @@ Use the command ``fioctl targets offline-update <target-name> <dst> --tag <tag>

Performing the Offline Update
-----------------------------

Before doing the offline update, make the offline update content accessible on a device, e.g., attach and mount the USB drive.

Use the ``aklite-offline`` CLI utility to perform an offline update.
Expand Down Expand Up @@ -152,19 +153,21 @@ Offline Update Considerations

* **Offline Update is not a packaged delivery**

The content provided by ``fioctl targets offline-update`` command should be packaged by the customer and verified by the client service.
The content provided by ``fioctl targets offline-update`` command should be packaged by you, and verified by the client service.

* **Offline Update does not provide a secure delivery**

Related to the bullet above, Foundries.io™ cannot provide secure delivery of offline update content since the customer should do the packaging and delivery.
Related to the bullet above, Foundries.io™ cannot provide secure delivery of offline update content since you should do the packaging and delivery.

* **Offline Update allows installing Targets from different Tags**

A custom client application should handle this case if it is not the intended behavior.
A custom client application should handle this case if it is not the intended behavior.

* **Online/Offline Mixed Updates**

Toggling between online and offline modes is not tested or validated by Foundries.io. It should be handled by a custom client application. Both cases can work together, but the offline update feature was initially designed to be offline only until the device was registered.
Toggling between online and offline modes is not tested or validated by Foundries.io.
It should be handled by a custom client application.
Both cases can work together, but the offline update feature is designed to be offline only, until the device is registered.

There are a few points to take into account by the custom client application:

Expand Down
Loading

0 comments on commit ce0fa3b

Please sign in to comment.