beamable / BeamableProduct

The beamable product suite including com.beamable, com.beamable.server, microservice base image, portal, the installer, and build scripts
Other
5 stars 0 forks source link

Implicit beamo manifest files #3350

Closed cdhanna closed 3 months ago

cdhanna commented 4 months ago
    "ServiceDefinitions": [
        {
            "BeamoId": "NotifTest",
            "Protocol": 0,
            "DependsOnBeamoIds": [],
            "ImageId": "",
            "ShouldBeEnabledOnRemote": true,
            "TruncImageId": ""
        }
    ],

BeamoId could be

  1. csproj file name, folder name, assembly name, "whatever the user typed when they said microservice create"
cdhanna commented 4 months ago

Here is the full manifest snippet for a local service, only.

{
    "ServiceDefinitions": [
        {
            "BeamoId": "NotifTest",
            "Protocol": 0,
            "DependsOnBeamoIds": [],
            "ImageId": "",
            "ShouldBeEnabledOnRemote": true,
            "TruncImageId": ""
        }
    ],
    "HttpMicroserviceLocalProtocols": {
        "NotifTest": {
            "DockerBuildContextPath": "services",
            "RelativeDockerfilePath": "NotifTest/Dockerfile",
            "BindSrcForHotReloading": {
                "IsReadOnly": false,
                "LocalPath": null,
                "InContainerPath": null
            },
            "HotReloadEnabledEndpoint": null,
            "HotReloadEnabledPort": null,
            "CustomPortBindings": [],
            "CustomBindMounts": [],
            "CustomVolumes": [],
            "CustomEnvironmentVariables": [],
            "InstanceCount": 1
        }
    },
    "HttpMicroserviceRemoteProtocols": {
        "NotifTest": {
            "HealthCheckEndpoint": "health",
            "HealthCheckPort": "6565",
            "CustomEnvironmentVariables": []
        }
    },
    "EmbeddedMongoDbLocalProtocols": {},
    "EmbeddedMongoDbRemoteProtocols": {}
}

Thinking about the ServiceDefinitions blob,

field comment
BeamoId could be the msbuild property defined in the csproj, or coalesce to the assembly name
Protocol inferfed from detecting a csproj file referencing the Beamable.Microservices.Runtime nuget package
DependsOnBeamoIds this is no longer necessary anymore, I think its not supposed to be in the JSON at all.
ImageId this refers to the image you'd deploy if you were going to deploy it. From a CLI workflow perspective, I don't think we need to put this here at all, see later comment about deployments
ShouldBeEnabledOnRemote see comment on deployments
TruncImageId see comment on deployments
Thinking about the HttpMicroserviceLocalProtocols blob field comment
(key) NotifTest this comes from the same logic as the BeamoId
DockerBuildContextPath we could infer this as the folder path containing the .beamable/ folder. This way, the entire beam context is part of the docker context. I'm not sure if there are docker related reasons to NOT have a giant build context.
RelativeDockerfilePath if we infer the DockerBuildContextPath, we'd just need to constrain the Dockerfile to live next to the csproj file, which feels like a mostly safe idea.
BindSrcForHotReloading Honestly, I think now that we can use dotnet watch without docker, we could simplify our lives by REMOVING hot reload with volumes inside docker. This way, docker builds would become mirrors of production releases
HotReloadEnabledEndpoint remove
HotReloadEnabledPort remove
CustomPortBindings remove
CustomBindMounts remove
CustomEnvironmentVariables remove
InstanceCount remove

Thinking about the HttpMicroserviceRemoteProtocols blob, honestly, I think we could hardcode all these properties. The idea that they are definable is cool, but it feels like premature optimization at this point. We have no use cases where these values AREN'T "health" and 6565. When we do, we can revisit.


There are some properties from the ServiceDefinitions blob that are about deployment only. When you do beam services deploy or beam services run, you are making a "deployment" either on the remote-realm, or your local docker service. In these cases, the services that turn on need to be defined somewhere. When you do beam services deploy, what you're really doing is pushing docker images to Beamable, and then POSTing a manifest file containing the service names, docker image ids, and enabled booleans.

This is the trickiest part to "infer", because the very nature of the use case is that the developer is SETTING values.

Perhaps, we should dramatically change the UX around doing deployments and local docker runs.

# deploy a beamo-schema manifest
beam services deploy --manifest=<path-to-manifest>

The above would be cool, and it would let us redeploy old manifests if they existed as json files. However, it doesn't answer how the manifest is generated if its the first deployment, or if the developer is modifying enablement or service-sizing (something we still don't support :cry: ).

A deployment is 2 major steps.

  1. upload docker images to Beamable,
  2. upload manifest file

I think we should separate these steps into separate commands.

# build, health-check, and upload service docker images. The result of this command produces the imageIds as a JSON blob.
beam services upload --ids=<filter>
{
    "uploads": {
        "NotifTest": {
            "imageId": "1234", 
            "success": true,
        }
    }
}

Then, separately,

beam services manifest new --output="./path.json"
# scans for projects, and requests imageId, and enabled value. 
# if there are remote instances of the service, it can inherit those values.

# the result of this command is a manifest file
beam services manifest push --manifest=<path>
# a combination of beam services upload, and beam services manifest
beam services deploy 

Use cases for deployment

  1. I want to deploy something for the first time
    
    beam services deploy

with no given --manifest flag, this defaults to declaring an implicit manifest from what is already deployed, and

merging in new services as enabled.

This then runs beam services upload, and beam services manifest push with the latest imageId variants


1. I want to update my services with the latest code.
```sh
beam services deploy
  1. I want to change which services are enabled.

    beam services manifest new --output=next.json
    # edit next.json
    beam services deploy --manifest=next.json 
  2. I want to delete a service.

    rm -rf NotifTest/
    beam services deploy
  3. I want to add a service.

    beam project new service AnotherTuna 
    beam services deploy
  4. I want to roll services.

    beam services manifest current --output=current.json
    beam services manifest push --manifest=specific.json
  5. I want to get an old deployment, and make a tweak to it.

    beam services manifest get --filter=<?>
    # edit specific manifest somehow
    beam services manifest push --manifest=specific.json
  6. I want to deploy the services to a local docker instance and see what happens

    beam services run 
  7. I want to deploy the services, with a specific manifest.

    
    beam services run --manifest=specific.json

if the source code for a service does not exist locally, this command will currently fail, but there is possibility that

we could add remote image download

cdhanna commented 4 months ago

docker build context defaults to .beamable folder root, but can be overridden not at the per project level, but at the per workspace level.

config-defaults.json

{
 // relative to parent of .beamable folder.
 "relative-docker-build-context": "."
}
cdhanna commented 4 months ago

put some stuff in the csproj

        <!-- When "true", this service will be deployed and run on the Beamable Cloud. When "false", this service will not run when deployed. -->
        <BeamEnabled>true</BeamEnabled>

        <!-- Beamable uses a RoutingPath to direct traffic to your service. By default, the routingPath is the beamoId. This property overrides the routingPath. -->
        <!-- <BeamOverrideRoutingPath>NotifTest</BeamOverrideRoutingPath> -->

        <!-- Force the deploy to use this imageId, if this property doesn't exist, then the current docker image will be built and the resulting Id used. -->
        <!-- <BeamOverrideTargetImageId>123</BeamOverrideTargetImageId>-->

We can remove the beamoid from the [Microservice] attribute, and also place all the config options as additional msbuild properties.

cdhanna commented 3 months ago

open questions that cause uncertainty-

  1. how do we read the csproj files?
  2. is it possible to sub-filter the tarball for the docker build image command?
cdhanna commented 3 months ago

part of this is being done by https://github.com/beamable/BeamableProduct/issues/3270

PedroRauizBeamable commented 3 months ago

Quick research: