Skip to content

Commit 37525c9

Browse files
authored
Merge pull request #49 from epics-containers/dev
add developer_container tutorial
2 parents 185e533 + 0dc11a5 commit 37525c9

File tree

2 files changed

+419
-0
lines changed

2 files changed

+419
-0
lines changed

docs/user/tutorials/dev_container.rst

Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
Developer Containers
2+
====================
3+
4+
.. _ioc_change_types:
5+
6+
Types of Changes
7+
----------------
8+
9+
Containerized IOCs can be modified in 3 distinct places (in order of decreasing
10+
frequency of change but increasing complexity):
11+
12+
#. The IOC instance: this means making changes to the IOC instance folders
13+
which appear in the ``iocs`` folder of a domain repository. e.g.:
14+
15+
- changing the EPICS DB (or the ``ibek`` files that generate it)
16+
- altering the IOC boot script (or the ``ibek`` files that generate it)
17+
- changing the version of the Generic IOC used in values.yaml
18+
- for Kubernetes: the values.yaml can override any settings used by helm
19+
so these can also be adjusted on a per IOC instance basis.
20+
- for Kubernetes: changes to the global values.yaml
21+
file found in ``beamline-chart``, these affect all IOCs in the domain.
22+
23+
#. The Generic IOC: i.e. altering how the Generic IOC container image
24+
is built. This means making changes to an ``ioc-XXX``
25+
source repo and publishing a new version of the container image.
26+
Types of changes include:
27+
28+
- changing the EPICS base version
29+
- changing the versions of EPICS support modules compiled into the IOC binary
30+
- adding new support modules
31+
- altering the system dependencies installed into the container image
32+
33+
#. The dependencies - Support modules used by the Generic IOC. Changes to support
34+
module repos. To make use of these changes would require:
35+
36+
- publishing a new release of the support module,
37+
- updating and publishing the Generic IOC
38+
- updating and publishing the IOC instance
39+
40+
For all of the above, the epics-containers approach allows
41+
local testing of the changes before going through the publishing cycle.
42+
This allows us to have a fast 'inner loop' of development and testing.
43+
44+
Also, epics-containers provides a mechanism for creating a separate workspace for
45+
working on all of the above elements in one place.
46+
47+
Need for a Developer Container
48+
------------------------------
49+
50+
The earlier tutorials were firmly in the realm of ``1`` above.
51+
It was adequate for us to install a container platform, IDE and python
52+
and that is all we needed.
53+
54+
Once you get to level ``2`` changes you need to have compilers and build tools
55+
installed. You might also require system level dependencies. AreaDetector,
56+
that we used earlier has a long list of system dependencies that need to be
57+
installed in order to compile it. Traditionally we have installed all of these
58+
onto developer workstations or separately compiled the dependencies as part of
59+
the build.
60+
61+
These tools and dependencies will differ from one Generic IOC to the next.
62+
63+
When using epics-containers we don't need to install any of these tools or
64+
dependencies on our local machine. Instead we can use a developer container,
65+
and in fact our Generic IOC *is* our developer container.
66+
67+
When the CI builds a Generic IOC it creates
68+
`two targets <https://github.com/orgs/epics-containers/packages?repo_name=ioc-adsimdetector>`_:
69+
70+
:developer: this target installs all the build tools and build time dependencies
71+
into the container image. It then compiles the support modules and IOC.
72+
73+
:runtime: this target installs only the runtime dependencies into the container.
74+
It also extracts the built runtime assets from the developer target.
75+
76+
The developer stage of the build is a necessary step in order to get a
77+
working runtime container. However, we choose to keep this stage as an additional
78+
build target and it then becomes a perfect candidate for a developer container.
79+
80+
VSCode has excellent support for using a container as a development environment.
81+
The next section will show you how to use this feature. Note that you can use
82+
any IDE that supports remote development in a container, you could also
83+
simply launch the developer container in a shell and use it via CLI only.
84+
85+
Starting a Developer Container
86+
------------------------------
87+
88+
For this section we will work with the ADSimDetector Generic IOC that we
89+
used in previous tutorials. Let's go and fetch a version of the Generic IOC
90+
source and build it locally.
91+
92+
For the purposes of this tutorial we will place the source in a folder right
93+
next to your test beamline ``bl01t`` folder. We will also be getting a
94+
specific version of the Generic IOC source so that future changes don't break
95+
this tutorial:
96+
97+
.. code-block:: bash
98+
99+
# starting from folder bl01t so that the clone is next to bl01t
100+
cd ..
101+
git clone --recursive [email protected]:epics-containers/ioc-adsimdetector.git -b 2023.10.6b1
102+
cd ioc-adsimdetector
103+
ec dev build
104+
105+
The last step uses one of the ``ec dev`` sub commands to build the developer
106+
target of the container to your local container cache. This will take a few
107+
minutes to complete. A philosophy of epics-containers is that Generic IOCs
108+
build all of their own support. This is to avoid problematic dependency trees.
109+
For this reason building something as complex as AreaDetector will take a
110+
few minutes when you first build it.
111+
112+
A nice thing about containers is that the build is
113+
cached so that a second build will be almost instant unless you have changed
114+
something that requires some steps to be rebuilt.
115+
116+
The ``ec dev`` commands are a set of convenience commands
117+
for working on Generic IOCs from *outside* of the container. These commands
118+
are useful for debugging container builds: although most work is done inside
119+
the container, you will need these commands if it fails to build.
120+
121+
Once built, open the project in VSCode:
122+
123+
.. code-block:: bash
124+
125+
code .
126+
127+
When it opens, VSCode may prompt you to open in a devcontainer. If not then click
128+
the green icon in the bottom left of the VSCode window and select
129+
``Reopen in Container``.
130+
131+
You should now be *inside* the container. All terminals started in VSCode will
132+
be inside the container. Every file that you open with the VSCode editor
133+
will be inside the container.
134+
135+
There are some caveats because some folders are mounted from the host file
136+
system. For example, the ``ioc-adsimdetector`` project folder
137+
is mounted into the container as a volume. It is mounted under
138+
``/epics/ioc-adsimdetector``. This means that you can edit the source code
139+
from your local machine and the changes will be visible inside the container and
140+
outside the container. This is a good thing as you should consider the container
141+
filesystem to be a temporary filesystem that will be destroyed when the container
142+
deleted.
143+
144+
Now that you are *inside* the container you have access to the tools built into
145+
it, this includes ``ibek``. The first command you should run is:
146+
147+
.. code-block:: bash
148+
149+
ibek ioc build
150+
151+
This generates an IOC source tree in the ``ioc`` folder under your
152+
``ioc-adsimdetector`` folder and compiles it. Note that the IOC code is
153+
boilerplate, but that the ``src/Makefile`` is generated according to the
154+
support modules this Generic IOC contains. You can go and take a look at
155+
the Makefile and see that it contains ``dbd`` and ``lib`` references for each
156+
of the support modules in the container.
157+
See ``/epics/ioc-adsimdetector/ioc/iocApp/src/Makefile``
158+
159+
You will note that the ``ioc`` folder is greyed out in the VSCode explorer. This
160+
is because it is in ``.gitignore`` and it is purely generated code. If you
161+
particularly needed to customize the contents of the ioc source tree then
162+
you can remove it from ``.gitignore`` and commit your changes to the repo. These
163+
changes would then always get loaded for every instance of the Generic IOC.
164+
165+
The Generic IOC should now be ready to run inside of the container. To do this:
166+
167+
.. code-block:: bash
168+
169+
cd ioc
170+
./start.sh
171+
172+
You will just see the default output of a Generic IOC that has no Instance
173+
configuration. Next we will add some instance configuration from one of the
174+
IOC instances in the ``bl01t`` beamline.
175+
176+
Let's now add some other folders to our VSCode workspace to make it easier to
177+
work with ``bl01t`` and to investigate the container.
178+
179+
Adding the Beamline to the Workspace
180+
------------------------------------
181+
182+
To meaningfully test the Generic IOC we will need an instance to test it
183+
against. We will use the ``bl01t`` beamline that you already made.
184+
185+
In VSCode click the ``File`` menu and select ``Add Folder to Workspace``.
186+
Navigate to ``/repos`` and you will see all the peers of your ``ioc-adsimdetector``
187+
folder (see `container-layout` below) . Choose the ``bl01t`` folder and add it to the
188+
workspace - you may see an error but if so clicking "reload window" will
189+
clear it.
190+
191+
Also take this opportunity to add the folder ``/epics`` to the workspace.
192+
193+
You can now easily browse around the ``/epics`` folder and see all the
194+
support modules and epics-base. This will give you a feel for the layout of
195+
files in the container. Here is a summary (where WS is the root
196+
of your host folders):
197+
198+
.. _container-layout:
199+
200+
.. list-table:: Developer Container Layout
201+
:widths: 25 35 45
202+
:header-rows: 1
203+
204+
* - Path Inside Container
205+
- Host Mount Path
206+
- Description
207+
208+
* - /epics/support
209+
- N/A
210+
- root of compiled support modules
211+
212+
* - /epics/epics-base
213+
- N/A
214+
- compiled epics-base
215+
216+
* - /epics/ioc-adsimdetector
217+
- WS/ioc-adsimdetector
218+
- Source repository for the Generic IOC
219+
220+
* - /epics/ioc
221+
- WS/ioc-adsimdetector/ioc
222+
- soft link to IOC source tree
223+
224+
* - /epics/ibek
225+
- N/A
226+
- All ibek *Support yaml* files
227+
228+
* - /epics/pvi
229+
- N/A
230+
- all PVI definitions from support modules
231+
232+
* - /epics/opi
233+
- N/A
234+
- all OPI files (generated or copied from support)
235+
236+
* - /repos
237+
- WS
238+
- all peers to Generic IOC source repo
239+
240+
241+
Now that we have the beamline repo visible in our container we can
242+
easily supply some instance configuration to the Generic IOC.
243+
Try the following:
244+
245+
.. code::
246+
247+
cd /epics/ioc-adsimdetector
248+
rm -r ioc/config
249+
ln -s /repos/bl01t/iocs/bl01t-ea-ioc-02/config ioc
250+
ioc/start.sh
251+
252+
This removed the boilerplate config and replaced it with the config from
253+
the IOC instance bl01t-ea-ioc-02. Note that we used a soft link, this
254+
means we can edit the config, restart the IOC to test it and the changes
255+
will already be in place in the beamline repo. You can even open a shell
256+
onto the beamline repo and commit and push the changes.
257+
258+
Wrapping Up
259+
-----------
260+
261+
We now have a tidy development environment for working on the Generic IOC,
262+
IOC Instances and even the support modules inside the Generic IOC, all in one
263+
place. We can easily test our changes in place too. In particular note that
264+
we are able to test changes without having to go through a container build
265+
cycle.
266+
267+
In the following tutorials we will look at how to make changes at each of the
268+
3 levels listed in `ioc_change_types`.

0 commit comments

Comments
 (0)