Closed richlander closed 2 years ago
For architecture, see https://github.com/ubuntu-rocks/dotnet/issues/19.
I'll throw out a proposal here: ubuntu/dotnet-<image-type>:<dotnet-version>-<ubuntu-version-codename>-<arch>
Example: ubuntu/dotnet-runtime:6.0-jammy-arm64v8
We can, of course, use multi-arch tags for things as well.
It would be good if the Canonical folks suggested a pattern that all Rocks use (or at least consider). I was thinking less about the registry repos (which is still an important topic) and more the GitHub repos. Ideally, there was a README that defined the pattern for both.
@cjdcordeiro
these concepts are still very much in progress.
I do have some preliminary structures I can share for the time being, but I'll only apply them to the project in a few weeks, once I gather more feedback and assess the technical feasibility.
For now, feedback is welcome. This is the current thinking:
ROCKS should adopt (to some extent) the existing channels
terminology from Snaps.
In practice, this means there are a few concepts one needs to be acquainted with when building a ROCK:
base
: the Ubuntu base upon which the ROCK has been built, version
: the version of the containerised software (6.0 in our current repo), risk
: one of "edge", "beta", "candidate" or "stable", revision
: an app-wide unique identifier, arch
: the architecture(s) of the ROCK,oci tag
: the main, immutable Docker tag,oci aliases
: mutable Docker tags (like latest
)
(there might be more in the future, but these are enough to get something going)For the time being, while our ROCKS infrastructure and release management are still coming to life, I'd propose organizing this .NET project as follows:
The ROCKs' recipes (Dockerfiles in this case) should all be located in the same place.
The ROCKs' builds are driven by the rockcraft.yaml
files located in the rock
folder.
~~dotnet/ ├── .github ├── tests # global scope tests ├── LICENSE ├── README.md └── rockcraft ├── rockcraft.runtime.yaml ├── Dockerfile.runtime.amd64 ├── Dockerfile.runtime.arm ├── rockcraft.runtime-deps.yaml ├── Dockerfile.runtime-deps.amd64 ├── Dockerfile.runtime-deps.arm ├── .dockerignore ├── runtime │ ├── install-slices │ ├── LICENSE # if it doesn't exist, defaults to the project LICENSE │ ├── README.md │ ├── src │ └── tests # local scope (unit) tests └── runtime-deps ├── install-slices ├── LICENSE ├── README.md ├── src └── tests~~
dotnet/
├── tests # global scope tests
├── rock
│ ├── rockcraft.2.runtime_22.04_build.yaml
│ ├── rockcraft.2.runtime_20.04_build.yaml
│ ├── rockcraft.1.runtime-deps_22.04_build.yaml
│ └── rockcraft.1.runtime-deps_20.04_build.yaml
├── README.md
├── LICENSE
├── .github
├── dotnet-runtime-deps
│ ├── tests # local scope (unit) tests
│ ├── src
│ ├── README.md
│ ├── LICENSE # if it doesn't exist, defaults to the project LICENSE
│ ├── install-slices
│ ├── .dockerignore
│ ├── Dockerfile.22.04
│ └── Dockerfile.20.04
└── dotnet-runtime
├── tests
├── src
├── README.md
├── LICENSE
├── install-slices
├── .dockerignore
├── Dockerfile.22.04
└── Dockerfile.20.04
You might be asking about: *what are the rockcraft..yaml** files? These are metadata files, indicating the existing projects (ROCKs) to be built. So each YAML fille will contain the following information:
base
) from which the ROCK is being based onEach rockcraft YAML file has 1 ROCK as an output!
Example of the rockcraft.1.runtime-deps_20.04_build.yaml
's content:
name: dotnet-runtime-deps # a folder with this name must exist. This is the final ROCK's name (eg "ubuntu/dotnet-runtime-deps:latest")
base: 20.04
architectures:
- build-for: [arm, amd64]
As described above, for each arch, let's, for now, have a dedicated Dockerfile with the corresponding architecture suffix.
The target architectures are defined by the driving rockcraft YAML file (as exemplified above).
Note: multi-arch ROCKs do not have the arch in the OCI tag name. So multi-arch ROCKs are in fact comprising OCI manifest lists, with one image manifest per architecture.
Rules:
--build-for
entries (arch names) must exist in $GOARCH and Docker supported archsversion
sLet's create separate branches for that. See below
So in the end, a branch name would look something like: /channels/<version>/<risk>
. Examples:
/channels/6.0/stable
/channels/6.0/stable
/channels/6.0
(defaults to risk=edge)/channels/7.0/candidate
base
sAs for
version
s, let's create multiple branches for this. So in the end, a branch name would look something like: /channels/<version>/<base>/<risk>
. Examples:-
/channels/6.0/20.04/stable
-
/channels/6.0/22.04/stable
-
/channels/6.0/22.10
(defaults to risk=edge)- /channels/7.0/20.04/candidate
The ROCKs bases are defined by the driving rockcraft YAML file (as exemplified above).
If the YAML file states something like name: foo
and base: bar
, then we expect to see a folder called foo
, with a Dockerfile named Dockerfile.bar
.
We still need to understand if we can do Continuous Delivery from the CI directly (mostly need to sort out how to securely define and use credentials, and how to define registry destinations). But, OCI Tags shall be driven by the channel structure exemplified above.
So, for now, to respect the aforementioned structure whilst still being aligned with all the existing Ubuntu "ROCKS", which means a valid OCI Tag would be ubuntu/dotnet-runtime:6.0-22.04_stable
.
For the OCI Tag example from above, the following tags would emerge: 6.0
and 6.0-22.04
, all pointing to 6.0-22.04_stable
, since that is the "most stable" .NET 6.0 on 22.04.
What is still TBD are other special tags like latest
and stable
, since these might point to any version
and any base
. Let me know if you have ideas.
~~---
Finally, you might be asking about: what are the rockcraft.rockcraft.runtime.yaml
tells us (and the CI infra) to look for Dockerfile.runtime.*
files and build them.~~
`Inside this
rockcraft.*.yaml` files we shall find the necessary metadata information to build the ROCKs. For now, let's just say the YAML content will be:~~
~~ name: dotnet-runtime # or dotnet-runtime-deps~~
This name
will dictate the name of the ROCK to build.
With all this being said, please note that this structure is just a means to an end since we can still progress with the current structure, by focusing on a single base and .NET version.
That will result in a lot of branches. Do you think we need a README that describes which are live/supported? With everything in main
, that is easy. With branches, not so much.
Have you thought about how CI and CD will work? I guess if you make a change, that's to just one branch and we only need to validate assets for that one branch. In terms of ship day, how do we reason about that? Will there be a global view of Rocks with a mapping to which branch that the rock lives in?
All the arches are together so producing multi-arch tags for a given configuration (like Ubuntu 22.04 + .NET 6.0) is straightforward. That's good.
We have a samples directory, which we use to ship samples based on our images. They are very useful since our samples are diagnostic. Do you think we should include them? Here they are: https://mcr.microsoft.com/en-us/product/dotnet/samples/about.
Multiple branches also implies that multiple versions of runtime-deps images would be built/published for each version
and base
. That's quite an explosion of images for something that you could literally have one image for. That one image could be tagged such that it maps to each version
and base
.
Good point, however, that issue could be handled via a global view of images and infra. That's what we're doing with .NET images, too. The fact that we only have one Dockerfile where there are multiple here is immaterial, right?
I guess it depends on the complexity of the infrastructure. For a simplistic system, each branch would have its own GitHub Actions to handle CI/CD. With such a system, my point here is that a multi-branch pattern would imply multiple versions of that image. A more complex system would be needed to avoid that with a multi-branch pattern.
Hi again and thanks for the feedback.
After taking your comments into account and with @woky 's big help, I've edited the previous proposal above: https://github.com/ubuntu-rocks/dotnet/issues/24#issuecomment-1171396382
Summary of changes:
bases
are not embedded into each base
)Outstanding concerns:
runtime
has changed
Do you think we need a README that describes which are live/supported?
With this current structure, branches only get built if you commit to them, so if we don't, no new builds are triggered. No need for special READMEs I'd say
Have you thought about how CI and CD will work?
Yes. The CI/CD is centralized, outside this repository, thus all the effort towards a generic normalization of the project structure, such that the same CI can also fit other ROCKs in the future (even if for a limited time)
I guess if you make a change, that's to just one branch and we only need to validate assets for that one branch.
Yes
In terms of ship day, how do we reason about that?
All ROCKs are built and shipped whenever new changes are introduced to the respective branch.
Will there be a global view of Rocks with a mapping to which branch that the rock lives in?
Yes. Whenever a central build happens, a branch/tag clone is created in the builder
repository (we own this repo).
Will there be a global view of Rocks with a mapping to which branch that the rock lives in?
I wouldn't consider samples to be ROCKs. I think this is something interesting to be discussed...but my gut feeling is that samples should be treated as auxiliary artefacts. How to handle them though, that's a good question. @richlander can you open a ticket on this?
A possible idea would be to not build samples within the ROCKs CI/CD, but in this repo itself, and upload them separately to a different registry namespace...(thinking out loud)
Multiple branches also implies that multiple versions of runtime-deps images would be built/published for each version and base.
Yes, that's the consequence of having a monolithic repository (check my comment above, under "outstanding concerns"). Sure, if the CI/CD was dedicated to this repo, we could do that, but the CI is generic, and I'd like to avoid having tailored and complicated conditions in our CI just to serve very specific cases which could be better resolved through other means (like splitting the repo)
hope this helps ;)
With this current structure, branches only get built if you commit to them, so if we don't, no new builds are triggered. No need for special READMEs I'd say
There are two good options (IMO): README for what's a live branch or delete branches that are no longer live. I gotta think our two organizations care equally deeply about communicating support levels to users. Leaving live branches for EOL versions don't seem good for that.
Samples
Fair enough.
https://github.com/ubuntu-rocks/dotnet/issues/27
Structure
If we're going to use branches, I think the approach that would make the most sense is a branch per Ubuntu version and all .NET versions within that branch. That would solve the runtime-deps issue that @mthalman raised and would allow Canonical to declare a support policy per branch w/rt Ubuntu.
thanks for the feedback.
wrt EOL, yes, the strategy is that 1) all ROCKs shall have self-contained information about EOL, and 2) the respective sources shall get archived (if we are talking about GitHub sources) at EOL. On top of that, sources will also have community health files, which include a SUPPORT.md file
thanks
If we're going to use branches, I think the approach that would make the most sense is a branch per Ubuntu version and all .NET versions within that branch. That would solve the runtime-deps issue that @mthalman raised and would allow Canonical to declare a support policy per branch w/rt Ubuntu.
we've considered this option as it is something we've also been using for other projects (thus why I've also proposed doing it in the 1st proposal). However, there are a few things to consider here:
In any case, this is not to say that one approach is wrong and another is right...the reality is that we need to be as generic as possible to accommodate a variety of ROCKs (at least the ones in https://hub.docker.com/u/ubuntu) without disrupting too much the most popular practices of OSS management.
Got it. That context helps.
We can look at what we do. It's nuanced in a somewhat similar way to what you raise:
We've found that this works super well for us. Our product has something like two dozen product repos, so this separation makes sense. We're thinking of having a separate monorepo projection of these two dozen product repos to enable scenarios that are hard today. However, I think we'd keep the dotnet-docker repo separate as it is today.
A nice benefit of our current system is that most (all?) of our Dockerfiles are generated from templates. We make changes to the templates and to some data files, and then run scripts that generate all the desired Dockerfiles. That's really nice to do from one branch with a single invocation.
I agree that branching on Ubuntu version probably doesn't make sense. We're clearly not going to branch on architecture. That leaves target version (like .NET version) as the only remaining pivot. We can branch on that or not at all. However, if we were to branch on .NET version, which version would be in main
? Latest LTS or latest (stable) version?
thanks for the info @richlander . I think @valentincanonical would be keen to read such feedback on how you handle EOL, since this is something he's been working on for ROCKs as well.
However, if we were to branch on .NET version, which version would be in main? Latest LTS or latest (stable) version?
This is an excellent question. Typically, main
corresponds to the latest, most stable development of the software. But in this case, we don't have source code in the repo. I think we can discuss this in more detail...
wrt to the main
branch, I propose we keep it, but populate it only with a README.md file. Why this decision:
@richlander sounds good?
populate
main
with only a README.md file
That works. It's good since its self-descriptive of the scheme. That's what I care about most. However, what will the branches be modeled as? I assume .NET version in the same way the repo you pointed me to was Ubuntu version. Yes?
We could put samples in main
, too. They would rely on the latest stable version. That's what our samples already do, in dotnet/dotnet-docker.
What do others think?
yes, branches are created per .NET version.
@MichaelSimons @mthalman you good with this plan?
Yep, sounds good to me.
Sounds good to me as well.
great, closing in favour of https://github.com/ubuntu-rocks/dotnet/issues/29
There are are multiple dimensions for us to consider (not all of which are versioning):
I'm thinking we're going to need some directories.