Skip to content
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

Change the default image registry for the Middleware images #137

Merged
merged 5 commits into from
Apr 14, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Change the default image registry for the Middleware images
  • Loading branch information
Artonus committed Apr 13, 2023
commit 51a34ea27bd329b953b9a8ae8581c1b84e05a269
8 changes: 4 additions & 4 deletions docs/Where_to_start/roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ https://5g-era.eu

*The 5G-ERA project was developed by the following partners under the [consortium](https://5g-era.eu/consortium/) with funding of the European Union's Horizon 2020 Research and Innovation programme under grant agreement No. 101016681.*

For workshops demostrations and tutorials visit our [Youtube Channel](https://www.youtube.com/channel/UCFn5FI9OYLA9_jTwl2cwdFA/videos )
For workshops demonstrations and tutorials visit our [Youtube Channel](https://www.youtube.com/channel/UCFn5FI9OYLA9_jTwl2cwdFA/videos )

<p align="left">
<img src="../img/MiddlewareArchitecture.png" alt="MiddlewareArchitecture"/>
Expand All @@ -24,15 +24,15 @@ Please, for the very initial description, setup and configuration, [follow](http
The 5G-ERA Middleware is designed to connect three layers of application networks. First, it combines the ROS network on which the Robot specific application runs with the resource layer network. The Kubernetes network is managed by the OSM and the SDN Controllers that are part of the resource enablement network.
The Middleware mainly operates on the Kubernetes network layer, designed as a cloud-native application. The Middleware is built on the microservices architecture and consists of several components:
* Gateway – It redirects the traffic across the Middleware system meaning rerouteing to the microservices within the system. It also handles the authentication and authorization process.
* Action Planner – Integrating the semantic knowledge of the vertical into resource planning. It is part of the vertical level life cycle management implemented by the middleware.
* Action Planner – Integrating the semantic knowledge of the vertical into resource planning. It is part of the vertical-level life cycle management implemented by the middleware.
* Resource Planner – The resource Planner is responsible for assigning the placement example, on the cloud, Edge to the tasks.
* Orchestrator – It orchestrates the process of the deployment of the resources. It is responsible for the vertical level lifecycle management of the deployed services
* Orchestrator – It orchestrates the process of the deployment of the resources. It is responsible for the vertical-level lifecycle management of the deployed services
* Redis Interface – Redis Interface allows the users to retrieve, insert and update data from/into the Redis-Server

The image below presents the conceptual architecture of the 5G-ERA Middleware and the connection between the associated services. The 5G-ERA Middleware has been designed to run in the Cloud and the Edge devices. Therefore, it can be always accessible and provide the best quality of service to the Robot by placement in the closest possible location.

<p align="center">
<img src="../img/Middleware_Architecture.png" alt="Middleware architecture"/ >
<img src="../img/Middleware_Architecture.png" alt="Middleware architecture" >
</p>

The 5G-ERA Middleware connects to the Redis Cluster, which allows sharing of semantic knowledge between all the instances of the 5G-ERA Middleware running in every Cloud and Edge device.
Expand Down
2 changes: 1 addition & 1 deletion k8s/central-api/central-api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ spec:
- name: awsecr-cred
containers:
- name: central-api
image: 394603622351.dkr.ecr.eu-west-1.amazonaws.com/central-api:edge
image: ghcr.io/5g-era/central-api:edge
imagePullPolicy: Always
resources:
limits:
Expand Down
10 changes: 5 additions & 5 deletions k8s/gateway/gateway_deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ spec:
spec:
nodeSelector:
kubernetes.io/os: linux
containers:
- name: gateway
image: 394603622351.dkr.ecr.eu-west-1.amazonaws.com/gateway:latest
imagePullPolicy: IfNotPresent
resources: {}
containers:
- name: gateway
image: ghcr.io/5g-era/gateway:latest
imagePullPolicy: IfNotPresent
resources: {}
42 changes: 21 additions & 21 deletions k8s/orchestrator/orchestrator.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,24 +32,24 @@ spec:
nodeSelector:
kubernetes.io/os: linux
imagePullSecrets:
- name: awsecr-cred
containers:
- name: orchestrator-api
image: 394603622351.dkr.ecr.eu-west-1.amazonaws.com/orchestrator-api:v0.2.2
imagePullPolicy: Always
resources: {}
env:
- name: AWS_IMAGE_REGISTRY
value: 394603622351.dkr.ecr.eu-west-1.amazonaws.com # to be replaced with real value
- name: REDIS_INTERFACE_API_SERVICE_HOST
value: redis-interface-api # to be replaced with real value
- name: REDIS_INTERFACE_API_SERVICE_PORT
value: "80"
- name: Middleware__Organization
value: 5G-ERA-DEV # to be replaced with real value
- name: Middleware__InstanceName
value: MiddlewareBED # to be replaced with real value
- name: Middleware__InstanceType
value: Edge # to be replaced with real value
- name: CENTRAL_API_HOSTNAME
value: central.api
- name: awsecr-cred
containers:
- name: orchestrator-api
image: ghcr.io/5g-era/orchestrator-api:v0.2.2
imagePullPolicy: Always
resources: {}
env:
- name: IMAGE_REGISTRY
value: ghcr.io/5g-era # to be replaced with real value
- name: REDIS_INTERFACE_API_SERVICE_HOST
value: redis-interface-api # to be replaced with real value
- name: REDIS_INTERFACE_API_SERVICE_PORT
value: "80"
- name: Middleware__Organization
value: 5G-ERA-DEV # to be replaced with real value
- name: Middleware__InstanceName
value: MiddlewareBED # to be replaced with real value
- name: Middleware__InstanceType
value: Edge # to be replaced with real value
- name: CENTRAL_API_HOSTNAME
value: central.api
20 changes: 10 additions & 10 deletions k8s/redis-interface/redis_interface_deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ spec:
spec:
nodeSelector:
kubernetes.io/os: linux
containers:
- name: redis-interface-api
image: 394603622351.dkr.ecr.eu-west-1.amazonaws.com/redis-interface-api:latest
imagePullPolicy: Always
resources: {}
env:
- name: REDIS_HOSTNAME
value: ec2-18-133-117-215.eu-west-2.compute.amazonaws.com # to be changed with real value
- name: REDIS_PORT
value: '6309' # to be changed with real value
containers:
- name: redis-interface-api
image: ghcr.io/5g-era/redis-interface-api:latest
imagePullPolicy: Always
resources: {}
env:
- name: REDIS_HOSTNAME
value: ec2-18-133-117-215.eu-west-2.compute.amazonaws.com # to be changed with real value
- name: REDIS_PORT
value: "6309" # to be changed with real value
10 changes: 5 additions & 5 deletions k8s/task-planner/task_planner_deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ spec:
spec:
nodeSelector:
kubernetes.io/os: linux
containers:
- name: task-planner-api
image: 394603622351.dkr.ecr.eu-west-1.amazonaws.com/task-planner-api:latest
imagePullPolicy: Always
resources: {}
containers:
- name: task-planner-api
image: ghcr.io/5g-era/task-planner-api:latest
imagePullPolicy: Always
resources: {}
77 changes: 36 additions & 41 deletions src/Orchestrator/Deployment/DeploymentService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,12 @@ public class DeploymentService : IDeploymentService
/// Redis Interface API client
/// </summary>
private readonly IRedisInterfaceClient _redisInterfaceClient;

private readonly IConfiguration _configuration;
private readonly IOptions<MiddlewareConfig> _mwConfig;

/// <summary>
/// Name of the AWS registry used
/// Name of the container registry used
/// </summary>
private readonly string _awsRegistryName;
private readonly string _containerRegistryName;

public DeploymentService(IKubernetesBuilder kubernetesBuilder,
IEnvironment env,
Expand All @@ -57,27 +55,27 @@ public DeploymentService(IKubernetesBuilder kubernetesBuilder,
_redisInterfaceClient = redisInterfaceClient;
_configuration = configuration;
_mwConfig = mwConfig;
_awsRegistryName = _env.GetEnvVariable("AWS_IMAGE_REGISTRY");
_containerRegistryName = _env.GetEnvVariable("IMAGE_REGISTRY") ?? "ghcr.io/5g-era";
}

/// <inheritdoc/>
public async Task<bool> DeployAsync(TaskModel task, Guid robotId)
{
bool isSuccess = true;
var isSuccess = true;
try
{
var k8SClient = _kubernetesBuilder.CreateKubernetesClient();
_logger.LogDebug("Entered DeploymentService.DeployAsync");
var deployments = await k8SClient.AppsV1.ListNamespacedDeploymentAsync(AppConfig.K8SNamespaceName);
var deploymentNames = deployments.Items.Select(d => d.Metadata.Name).OrderBy(d => d).ToArray();
var deploymentNames = deployments.Items.Select(d => d.Metadata.Name).OrderBy(d => d).ToList();
_logger.LogDebug("Current deployments: {deployments}", string.Join(", ", deploymentNames));

BaseModel location = _mwConfig.Value.InstanceType.ToLower() == "cloud"
? (await _redisInterfaceClient.GetCloudByNameAsync(_mwConfig.Value.InstanceName)).ToCloud()
: (await _redisInterfaceClient.GetEdgeByNameAsync(_mwConfig.Value.InstanceName)).ToEdge();

foreach (var seq in task.ActionSequence!)
{
//BaseModel location;
//location = seq.PlacementType.ToLower().Contains("cloud")
// ? await _redisInterfaceClient.GetCloudByNameAsync(seq.Placement)
// : await _redisInterfaceClient.GetEdgeByNameAsync(seq.Placement);
foreach (var service in seq.Services!)
{
try
Expand All @@ -87,8 +85,7 @@ public async Task<bool> DeployAsync(TaskModel task, Guid robotId)
continue;

await DeployService(k8SClient, service, deploymentNames);
// TODO: add relation between actual cloud / edge definition and instance
//await _redisInterfaceClient.AddRelationAsync(service, location, "LOCATED_AT");
await _redisInterfaceClient.AddRelationAsync(service, location, "LOCATED_AT");
}
catch (Exception ex)
{
Expand Down Expand Up @@ -138,7 +135,7 @@ private async Task<bool> SaveActionSequence(TaskModel task, Guid robotId)
return result;
}

private async Task DeployService(IKubernetes k8SClient, InstanceModel service, string[] deploymentNames)
private async Task DeployService(IKubernetes k8SClient, InstanceModel service, List<string> deploymentNames)
{
_logger.LogDebug("Querying for redis for service {Id}", service.Id);
var imagesResponse = await _redisInterfaceClient.ContainerImageGetForInstanceAsync(service.Id);
Expand All @@ -159,18 +156,16 @@ private async Task DeployService(IKubernetes k8SClient, InstanceModel service, s

if (deploymentNames.Contains(cim.Name))
{
//TODO: handle the check if the deployment or a service already exists
continue;
var guidSuffix = Guid.NewGuid().ToString().Split('-')[3];
cim.Name = $"{cim.Name}-{guidSuffix}";
}

deploymentNames.Add(cim.Name);
var deployedPair = await Deploy(k8SClient, cim);

service.ServiceStatus = ServiceStatus.Idle.GetStringValue();
service.ServiceInstanceId = deployedPair.InstanceId;
_logger.LogDebug("Deployed the image {Name} with the Id {ServiceInstanceId}", service.Name,
service.ServiceInstanceId);

//TODO: assign values to the instance data
}
}

Expand All @@ -180,7 +175,7 @@ private async Task DeployService(IKubernetes k8SClient, InstanceModel service, s
/// <param name="k8SClient"></param>
/// <param name="cim"></param>
/// <returns></returns>
public async Task<DeploymentPairModel> Deploy(IKubernetes k8SClient, ContainerImageModel cim)
private async Task<DeploymentPairModel> Deploy(IKubernetes k8SClient, ContainerImageModel cim)
{
var instanceId = Guid.NewGuid();

Expand Down Expand Up @@ -222,7 +217,7 @@ private async Task<T> Deploy<T>(IKubernetes k8SClient, string objectDefinition,
}

var sanitized = objectDefinition.SanitizeAsK8SYaml();
T obj = KubernetesYaml.Deserialize<T>(sanitized);
var obj = KubernetesYaml.Deserialize<T>(sanitized);

if (obj == null)
{
Expand All @@ -232,29 +227,30 @@ private async Task<T> Deploy<T>(IKubernetes k8SClient, string objectDefinition,
if (obj is V1Service srv)
{
srv.Metadata.SetServiceLabel(instanceId);

srv.Metadata.Name = name;
obj = await k8SClient.CoreV1.CreateNamespacedServiceAsync(srv, AppConfig.K8SNamespaceName) as T;
return obj;
}

if (obj is V1Deployment depl)
if (obj is V1Deployment deployment)
{
depl.Metadata.SetServiceLabel(instanceId);
depl.Metadata.AddNetAppMultusAnnotations(AppConfig.MultusNetworkName);
foreach (var container in depl.Spec.Template.Spec.Containers)
deployment.Metadata.SetServiceLabel(instanceId);
deployment.Metadata.AddNetAppMultusAnnotations(AppConfig.MultusNetworkName);
deployment.Metadata.Name = name;
foreach (var container in deployment.Spec.Template.Spec.Containers)
{
List<V1EnvVar> envVars = container.Env is not null
var envVars = container.Env is not null
? new List<V1EnvVar>(container.Env)
: new List<V1EnvVar>();

envVars.Add(new("NETAPP_ID", instanceId.ToString()));
envVars.Add(new("MIDDLEWARE_ADDRESS", AppConfig.GetMiddlewareAddress()));
envVars.Add(new("MIDDLEWARE_REPORT_INTERVAL", 5.ToString()));
envVars.Add(new V1EnvVar("NETAPP_ID", instanceId.ToString()));
envVars.Add(new V1EnvVar("MIDDLEWARE_ADDRESS", AppConfig.GetMiddlewareAddress()));
envVars.Add(new V1EnvVar("MIDDLEWARE_REPORT_INTERVAL", 5.ToString()));

container.Env = envVars;
}

obj = await k8SClient.AppsV1.CreateNamespacedDeploymentAsync(depl, AppConfig.K8SNamespaceName) as T;
obj = await k8SClient.AppsV1.CreateNamespacedDeploymentAsync(deployment, AppConfig.K8SNamespaceName) as T;
return obj;
}

Expand Down Expand Up @@ -295,12 +291,12 @@ public async Task<bool> DeletePlanAsync(ActionPlanModel actionPlan)
bool retVal = true;
try
{
var k8sClient = _kubernetesBuilder.CreateKubernetesClient();
var k8SClient = _kubernetesBuilder.CreateKubernetesClient();
foreach (var action in actionPlan.ActionSequence)
{
foreach (var srv in action.Services!)
{
retVal &= await DeleteInstance(k8sClient, srv.ServiceInstanceId);
retVal &= await DeleteInstance(k8SClient, srv.ServiceInstanceId);
}
}
}
Expand Down Expand Up @@ -369,26 +365,26 @@ public async Task DeployActionAsync(Guid actionPlanId, Guid actionId)
return;

var deployments = await kubeClient.AppsV1.ListNamespacedDeploymentAsync(AppConfig.K8SNamespaceName);
var deploymentNames = deployments.Items.Select(d => d.Metadata.Name).OrderBy(d => d).ToArray();
var deploymentNames = deployments.Items.Select(d => d.Metadata.Name).OrderBy(d => d).ToList();

_logger.LogDebug("Retrieving location details (cloud or edge)");
BaseModel thisLocation = _mwConfig.Value.InstanceType == LocationType.Cloud.ToString()
? (await _redisInterfaceClient.GetCloudByNameAsync(_mwConfig.Value.InstanceName)).ToCloud()
: (await _redisInterfaceClient.GetEdgeByNameAsync(_mwConfig.Value.InstanceName)).ToEdge();

foreach (var instance in action.Services!)
{
_logger.LogDebug("Deploying instance '{0}', with serviceInstanceId '{1}'",
instance.Name, instance.ServiceInstanceId);
await DeployService(kubeClient, instance, deploymentNames);

_logger.LogDebug("Adding new relation between instance and current location");
await _redisInterfaceClient.AddRelationAsync(instance, thisLocation, "LOCATED_AT");
}

action.Placement = _mwConfig.Value.InstanceName;
action.PlacementType = _mwConfig.Value.InstanceType;

_logger.LogDebug("Saving updated ActionPlan");
await _redisInterfaceClient.ActionPlanAddAsync(actionPlan);
}
Expand Down Expand Up @@ -434,7 +430,6 @@ private async Task<bool> DeleteInstance(IKubernetes kubeClient, Guid instanceId)
}

/// <inheritdoc/>
/// <param name="tag1"></param>
public V1Deployment CreateStartupDeployment(string name, string tag)
{
var mwConfig = _configuration.GetSection(MiddlewareConfig.ConfigName).Get<MiddlewareConfig>();
Expand Down Expand Up @@ -470,7 +465,7 @@ public V1Deployment CreateStartupDeployment(string name, string tag)
var container = new V1Container()
{
Name = name,
Image = K8SImageHelper.BuildImageName(_awsRegistryName, name, tag),
Image = K8SImageHelper.BuildImageName(_containerRegistryName, name, tag),
ImagePullPolicy = AppConfig.AppConfiguration == AppVersionEnum.Prod.GetStringValue()
? "Always"
: "IfNotPresent",
Expand Down
8 changes: 4 additions & 4 deletions src/RedisInterface.Sdk/IRedisInterfaceClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@ public interface IRedisInterfaceClient
/// <summary>
/// Create graph relation between objects
/// </summary>
/// <param name="source"></param>
/// <param name="direction"></param>
/// <param name="name"></param>
/// <param name="source">Initiating point of a relation</param>
/// <param name="direction">Receiving point of a relation</param>
/// <param name="name">Name of the relation</param>
/// <typeparam name="TSource">Object that derives from <see cref="BaseModel"/></typeparam>
/// <typeparam name="TDirection">Object that derives from <see cref="BaseModel"/></typeparam>
/// <returns>Have relation been created</returns>
Expand All @@ -62,7 +62,7 @@ Task<bool> DeleteRelationAsync<TSource, TDirection>(TSource source, TDirection d
Task<List<RelationModel>?> GetRelationForActionAsync(Guid id, string relationName);

/// <summary>
/// Get the relations with the specified name that are outcoming from the specified object
/// Get the relations with the specified name that are out-coming from the specified object
/// </summary>
/// <typeparam name="TSource">Type of the source object</typeparam>
/// <param name="source">Source object that relation initiates from</param>
Expand Down