-
Notifications
You must be signed in to change notification settings - Fork 759
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Registry - Potential OCI Artifacts user experience #3283
Comments
This will be updated in the future after discussions with OCI SMEs. |
Imagine an issue of importing a bicep module from one ACR to another (e.g. airgapped). The problem is that if the references to the dependent modules are hardcoded then simply migrating is not enough, as also the contents need to be updated. We are facing a similar problem with helm charts and the problem is well described at https://stevelasker.blog/2020/10/21/is-it-time-to-change-default-registry-references/ and a discussion is at opencontainers/artifacts#29. @majastrz - can you think of a way to make the ACR hostname configurable (through command line or env variable) so bicep modules are transferrable between registries? Bonus question: how one can transfer a bicep module with all dependent modules from one registry to another without the need to discover all dependent modules? |
This is a great point. To support these scenarios, we would need to separate the registry URI from the Bicep files themselves. This is similar to how NuGet configures sources via the My preference is for a config file based approach (with cmd overrides) instead of a purely cmd-based solution to make it possible for the language server to consume this information and provide a good completion experience for external modules. Question: Do you always point to a single ACR? Or are there ever cases where you're pulling images/artifacts from multiple ACRs?
The idiomatic OCI method of dealing with dependencies appears to be to build them into the artifact at |
To avoid disruption or uncontrolled variation of the dependencies (e.g. tag update), we pull all dependencies into a test ACR first and deploy to test environments from there. Later in the release pipeline import the exact same versions to production ACR and run deploy to production environments from there. The ultimate test if all dependencies have been correctly captured and imported to production ACR is an isolated environment, where nothing can be pulled from outside. |
If most users would end up with a single registry, then maybe we should have a concept of a "default" registry. Then, the references could become |
Fair point, the "default" registry could be the current registry, while still have the ability to pull other modules from public sources within the same template. |
Yeah, we'd support the default and additional registries and ensure the references in the bicep file are/can be registry uri agnostic. |
I think there is a danger in default registries in that where the image comes from is abstracted away so it is not immediately obvious. What if you forget to set your default registry? Suddenly you might be downloading your packages from 'a public default' registry instead of your private registry. This helps create supply chain attacks which we've seen a lot of reports on lately. If the option of a default registry gets added there should not be any 'default for the default' imo. And I think it should still be allowed to be explicit about your registry location if you wish. |
@SteveLasker given your article at https://stevelasker.blog/2020/10/21/is-it-time-to-change-default-registry-references/, I'd love to hear/see your thoughts on how we should approach referencing Bicep modules from an OCI registry 😊 |
There's a bunch of lessons to learn from various registry attempts. The other thing I think we've learned is never, never, ever, not ever or never, have a search path. Where you can provide a list of registries you should look for. This leads to the registry squatting attack. @majastrz I did do a bit more thoughts on deterministic mappings: https://github.com/SteveLasker/drafts/blob/main/registry-repo-config.md The idea here is you can configure a registry, you can define deterministic mappings. And, you can use named parameters. Trying to change an existing toolchain is a challenge (like the container toolchains), although we should try. |
FWIW, I created this discussion topic: Registry Configurations #6 to continue thoughts across multiple artifact types. |
Thanks @SteveLasker! I definitely agree on the these points:
I took a look at https://github.com/SteveLasker/drafts/blob/main/registry-repo-config.md. I was definitely not considering the need to redirect to a different "path" in a particular registry, but that will be necessary if a smaller registry is being replicated to a larger one or one with a different naming convention. I'm not yet convinced that we need variables in the first iteration of the Bicep registry, but we should not make any decisions that prevent us from adding them later on. I'll write up a proposal of what this would look like and post it in this issue, so we can discuss. |
Config fileWe can add a new {
"registries": {
"aliases": {
"public": {
"uri": "mcr.microsoft.com"
},
"private": {
"uri": "example.azurecr.io"
},
"privateWithPath": {
"uri": "example.azurecr.io/hello/there"
}
}
}
} When the The JSON language service would provide completions for all the elements of the config file (except URIs, of couse 🙂). Module referencesAssuming the above // pulls example.azurecr.io/bicep/modules/myAmazingModule:0.1-alpha
module mod 'oci::private:bicep/modules/myAmazingModule:0.1-alpha' = {
...
}
// pulls mcr.microsoft.com/bicep/modules/role-assignment:1.42
module mod 'oci::public:bicep/modules/role-assignment:1.42' = {
...
}
// pulls example.azurecr.io/hello/there/something/else:1.0
module mod 'oci::privateWithPath:something/else:1.0' = {
...
} In addition to making the Bicep source agnostic to the registry URI, the above reference string syntax allows us to provide completions for all segments. (Alias completions would come from the config file. OCI repo and tag completions for private registries would come from ACR APIs. Completions for the public registry - TBD.) To help with prototyping, we will also allow a direct URI syntax like the following: module mod 'oci::mcr.microsoft.com/bicep/modules/myAmazingModule:0.1-alpha' =
{
...
} CLI supportTo allow pulling from a different registry Uri without modifying the .bicep source, the user could modify the Thoughts? |
@majastrz, Just to possibly anticipate the question as i’m not sure when I’ll be back online, the theory is there is not “one” public registry. Content can come from anyplace, as a company may have their corporate registry (registry.acme-rockets.io/corp/some-package:v1) which is their “public” and each team, or sub-division of the company may have theirs. |
I think uri's should be allowed instead of aliases in the module reference. I don't see the harm in giving the choice. Say I'm prototyping and trying out an external module. Now I have to create the Bicep.json only because I need to reference the registry. To make it easier to distinguish between aliases and uris we could for example reserve the 'special' alias uri: module mod 'oci::uri:mcr.microsoft.com/bicep/modules/myAmazingModule:0.1-alpha' = { ... } |
@SteveLasker Thanks for taking a look (especially during your time off)!
Yup, they'd just be arbitrary names. No special meaning. I updated the proposal above to clarify as well.
Yeah, no restrictions on the number of public registries. I guess the only real difference is whether you need to auth and if your identity has permissions to pull artifacts (and list artifacts to power completions when authoring). Although even that line gets blurry with the move to block anynomous requests on some registries like docker hub.
@rouke-broersma Yeah I think that makes sense as well. I updated the proposal above to add a similar syntax to the above. The final syntax should be similar - I'm ignoring any issues with parsing ambiguities right now. |
Team discussion notes 8/9/2021
The alternatives for the prefix would look like this:
Thoughts? |
I would personally say that the bicepconfig.json should only be used for aliases and that there should simply never be any 'default' alias. Which would mean that if the alias is not set, the full oci url needs to be referenced or the alias has to be passed through the cli. No magic referencing at all even for the from your standpoint 'default' of mcr. The reason is that this would still be a 'fallthrough search path' which can lead to supply chain attacks based on name-squatting. This is not a theoretical attack, it happens with other registry infrastructure right now. |
To allow Bicep code to be easily configured/shared, it would be very good to have an alias type of functionality to have 'variable' config for the registries used. I also agree that having a bicepConfig.json requirement for managing aliases will add some friction to the user experience. If the Bicep code (.bicep) uses aliases for registries and does not contain the actual references to the registries, I think sharing source code (also those that does not use the default registry) and examples will become harder than necessary and minimize the insight into which repository is used. With that said, having the opportunity to easily set an alias can be handy for both readability and maintaining code. Is it feasible to contain the reference to the registries within the .bicep files, but not verbosely on each reference? E.g. something like: registryAlias myReg = 'example.azurecr.io'
module mod 'bmr::myReg:bicep/modules/myAmazingModule:0.1-alpha' = {
...
} which could be overwritable with cli flags: bicep [subcommand] --registry-alias myRegAlias=example.azurecr.io |
@matsest scroll up to #3283 (comment). I have proposal above that covers something like that but with alias config stored in |
After a team discussion, we have decided to use the following verbs for the CLI command:
|
@matsest If we allowed variables to be used in type strings (via constant folding), the syntax would have to be something like |
Closing since this has been fully implemented |
Goals
This is intended to provide an approximation of the Bicep registry experience IF we chose OCI Artifacts as the package manager and implement the integration. The existence of this issue DOES NOT indicate that OCI was selected as the implementation of the Bicep Registry. (See #2128 for details about other candidates.)
Gallery Experience
TBD
CLI
bicep build
Since Bicep modules can contain references to modules published to an artifact registry, the artifact contents may not exist on the local system. If the Bicep file contains references to external modules,
bicep build
pulls the referenced artifacts before type checking and code generation and stores them on the local file system. (In the compiler pipeline, the pull step occurs after parsing but before type checking is done.)By default, the artifact cache is located at
%USERPROFILE%\.bicep\artifacts on Windows
and~/.bicep/artifacts
on Linux and Mac. The location can be customized via theBICEP_ARTIFACTS
environment variable. (If the language server and CLI tools are pointed to different artifact cache paths, they will each download a separate copy of each referenced artifact.)bicep pull
In certain usecases (Docker and some CI systems), the restore and build operations need to be separated. This can be accomplished as follows:
bicep pull
bicep build --no-pull main.bicep
Reference module from an artifact
To reference a module from a package, the opens a new or existing Bicep file in VS code and types one or more declarations like the following:
OCI does not have a concept of a package feed like NuGet does. Instead, references are made directly via a URI. The URI has the following components:
majastrzoci.azurecr.io
- URI of the registrybicep/modules/test
- Identifies the repository. A repository is a collection of artifacts with the same name but different tags.0.1-alpha
- Identifies the artifact tag, which is similar to a package version in NuGet. (However, the same image/artifact content may have multiple tags or may be untagged.)See https://docs.microsoft.com/en-us/azure/container-registry/container-registry-concepts for more details.
OCI also allows referencing artifacts by their SHA256 digest. The syntax for this would look like the following:
No mechanism exists to enumerate all possible registry URIs, which means we will NOT be able to provide completions for the registry URI portion of the module type string. Once the registry URI is typed in (and auth is setup), we will be able to provide completions for the image name and tags.
If the current module has any external module references, the language server queues up a pull action in the background. The background process will check the package cache for the artifact name and tag. If missing, the package will be downloaded from the registry.
The background pull operation does not happen instantly. Until the artifact is in the local artifact cache, accurate type information is not available:
any
orobject
)If/when restore fails:
Once the background pull operation is finished successfully, the language server recompiles the module to make use of the downloaded type info (we can reuse the parse tree). Property name and property access completions are now available for the module.
Setup private registry
Several registries support OCI artifacts. A good list is available at https://oras.land/implementors/. An Azure Container Registry can be easily created via the Azure Portal or a
.bicep
file.Setup local registry
Using a local docker installation, you can run the
registry
image:This makes a non-persistent registry available at
localhost:5000
.Create package
OCI artifacts are either pushed from local file system to a registry or pulled from the registry down to the local file system. (It is also possible to transfer artifacts between registries, but it's less relevant here.) There is no "package" concept that is a single-file representation of all the layers in an OCI artifact that would be equivalent to a .nupkg in NuGet or similar in other package managers.
Push artifact to registry
An artifact can be pushed to the registry via the
bicep push <file>
command. The command performs the following operations:--no-pull
)The artifact contents will be as follows:
A more detailed discussion about package contents is tracked in #3266. The discussion of module metadata lives in #3187.
Sign artifact
TBD
The text was updated successfully, but these errors were encountered: