compose-x / ecs_composex

Manage, Configure and Deploy your services and AWS services and applications from your docker-compose definitions
https://docs.compose-x.io
Mozilla Public License 2.0
158 stars 16 forks source link

[FR] Use/lookup for load balancer #746

Closed zahornyak closed 3 months ago

zahornyak commented 3 months ago

Is your feature request related to a problem? Please describe. Currently, I want to use existing load balancer for my preset, but I cannot do that or there are no docs that I can do that

Describe the solution you'd like I would like to have possibility to use use/lookup for x-elbv2

Describe alternatives you've considered didnt find any

JohnPreston commented 3 months ago

hello @zahornyak That is a complete docs oversight on my end, x-elbv2.Lookup is available in version 1.x Let me make sure to have this documented.

zahornyak commented 3 months ago

@JohnPreston you're right. But how to use that? When I use it like that:

x-elbv2:
  Lookup:
    loadbalancer:
      Tags:
        - Name: test-balancer

it does not work

I have errors like that: jsonschema.exceptions.ValidationError: {'loadbalancer': {'Tags': [{'Name': 'test-balancer'}]}} is not valid under any of the given schemas

JohnPreston commented 3 months ago

So, the error here is just telling you that the Lookup format is incorrect. God knows why I originally had Tags: List[{key: value}] instead of just Tags: {key: value} You can always double check with the JSON schema spec.

x-elbv2:
  Lookup:
    loadbalancer:
      Tags:
        Name: test-balancer

Should work, on top of my head

zahornyak commented 3 months ago

@JohnPreston

x-elbv2:
  Lookup:
    loadbalancer:
      Tags:
        Name: test-balancer

didnt work. jsonschema.exceptions.ValidationError: {'loadbalancer': {'Tags': {'Name': 'test-balancer'}}} is not valid under any of the given schemas

JohnPreston commented 3 months ago

@zahornyak what version of compose-x are you using? Latest is 1.0.1, latest nightly is 1.1.0rc1 Also note that the logical name of the LB is missing

x-elbv2:
  my-lb-to-lookup-logical-name:
    Lookup:
      loadbalancer:
        Tags:
          Name: test-balancer
zahornyak commented 3 months ago

Update: After some time of investigation, I found the required parameters that should exist in the lookup which are 'TargetGroups' or 'Services'

JohnPreston commented 3 months ago

Update: After some time of investigation, I found the required parameters that should exist in the lookup which are 'TargetGroups' or 'Services'

So is it working now? Do you mind if I tag you to review the docs when I open the PR for it? Feel free to report anything not working :)

zahornyak commented 3 months ago

@zahornyak what version of compose-x are you using? Latest is 1.0.1, latest nightly is 1.1.0rc1 Also note that the logical name of the LB is missing

x-elbv2:
  my-lb-to-lookup-logical-name:
    Lookup:
      loadbalancer:
        Tags:
          Name: test-balancer

yeah, I missed that part, but now I've added everything and it works as well. Thank you

zahornyak commented 3 months ago

Update: After some time of investigation, I found the required parameters that should exist in the lookup which are 'TargetGroups' or 'Services'

So is it working now? Do you mind if I tag you to review the docs when I open the PR for it? Feel free to report anything not working :)

sure) Thanks

zahornyak commented 3 months ago

@JohnPreston I have an additional question regarding load balancer listener rules. As I can see, I can lookup for the listeners but can I lookup for listeners and create listener rules in that listener? I'm currently doing this:

x-elbv2:
  lb:
    Lookup:
      loadbalancer:
        Tags:
          Name: test-deleteme
      Listeners:
        1:
          Tags:
            Name: test-deleteme
          Targets:
            - name: all-gateways
              access: test.com

    TargetGroups:
      all-gateways:
        Port: 80
        Protocol: TCP
        HealthCheck:
          HealthCheckIntervalSeconds: 17
          HealthCheckProtocol: TCP
          HealthCheckTimeoutSeconds: 10
          HealthyThresholdCount: 2
          UnhealthyThresholdCount: 2
        TargetGroupAttributes:
          deregistration_delay.timeout_seconds: "30"
        Services:
          - Name: web:web
            Port: 80

But it does not create any listener rules with a connected target group there.

JohnPreston commented 3 months ago

Okay, interesting. The way you have TargetGroups instead of using Services though is when you want multiple services to be part of a singular target group. Instead I'd say, use Services as follows

x-elbv2:
  my-lb:
    DnsAliases:
      - Names:
          - my-domain.tld
        Route53Zone: x-route53::PublicZone
    Lookup:
      loadbalancer:
        Tags:
          servicename: some-service-name
          project: project-name
          Name: lb-name
      Listeners:
        443:
          Tags:
            Name: https-listener
            Port: "443"
            Protocol: HTTPS
          Targets:
            - name: family:service:8080
              Conditions:
                - Field: host-header
                  HostHeaderConfig:
                    Values:
                      - my-domain.tld

    Services:
      family:service:8080:
        port: 8080
        protocol: HTTP
        healthcheck: 8080:HTTP:7:2:15:5:/swagger-ui.html:401

This is an actual working example that I use and works great. I will document it all which will get me to review and check bits and bobs in the code.

zahornyak commented 3 months ago

Thanks for the example

How did you get 8080 on family configurations? I have errors that Could not find 80 in family web

Also, I have an error TypeError: string indices must be integers when using your example.

Here's my config:

version: "3.8"

x-cluster:
  Properties:
    CapacityProviders:
      - FARGATE
    ClusterName: Test-cluster

x-vpc:
  Lookup:
    VpcId:
      Tags:
        - Name: default
    AppSubnets: {}
    PublicSubnets:
      Tags:
        - name: public
    PrivateSubnets: {}
    StorageSubnets: {}

x-elbv2:
  lb:
    Lookup:
      loadbalancer:
        Tags:
          Name: test-deleteme
      Listeners:
        1:
          Tags:
            Name: test-deleteme
          Targets:
            - name: web:api
              Conditions:
                - Field: host-header
                  HostHeaderConfig:
                    Values:
                      - my-domain.tld

    Services:
      web:api:
        port: 80
        protocol: HTTP
        healthcheck: 80:HTTP:7:2:15:5:/:401

services:
  api:
    image: nginx
    ports:
      - "80:80"
    networks:
      - public
    deploy:
      labels:
        ecs.task.family: web

networks:
  public:
    x-vpc: PublicSubnets

Did I miss something?

zahornyak commented 3 months ago

@JohnPreston As far as I can see, error TypeError: string indices must be integers only exist when I specify:

          Targets:
            - name: web:api
              Conditions:
                - Field: host-header
                  HostHeaderConfig:
                    Values:
                      - my-domain.tld

And I have no idea why it doesn't work. And still interested in how family:service:8080 formed. I couldn't do the same

JohnPreston commented 3 months ago

Thanks for the example

How did you get 8080 on family configurations? I have errors that Could not find 80 in family web

Also, I have an error TypeError: string indices must be integers when using your example.

Here's my config:

version: "3.8"

x-cluster:
  Properties:
    CapacityProviders:
      - FARGATE
    ClusterName: Test-cluster

x-vpc:
  Lookup:
    VpcId:
      Tags:
        - Name: default
    AppSubnets: {}
    PublicSubnets:
      Tags:
        - name: public
    PrivateSubnets: {}
    StorageSubnets: {}

x-elbv2:
  lb:
    Lookup:
      loadbalancer:
        Tags:
          Name: test-deleteme
      Listeners:
        1:
          Tags:
            Name: test-deleteme
          Targets:
            - name: web:api
              Conditions:
                - Field: host-header
                  HostHeaderConfig:
                    Values:
                      - my-domain.tld

    Services:
      web:api:
        port: 80
        protocol: HTTP
        healthcheck: 80:HTTP:7:2:15:5:/:401

services:
  api:
    image: nginx
    ports:
      - "80:80"
    networks:
      - public
    deploy:
      labels:
        ecs.task.family: web

networks:
  public:
    x-vpc: PublicSubnets

Did I miss something?

My example with family:service:8080 was due to my service having 8080 in ports. This is something you want to set if the service of the same family has more than one port, each going to be a different target group, therefore the family:service goes into family:service:port as the specific port of the container is the target.

I presume you removed the AppSubnets Tags? Even if you are not going to deploy to it, AppSubnets, StorageSubnets and PublicSubnets are currently required to be found in your vpc, even if they are the same for all 3. PrivateSubnets is not required however, unless you have a need for them of course.

Listeners:
  1: {}

I presume that you set 1 for example here? Otherwise, I highly recommend you use the actual listener port number for clarity.

For the TypeError, I imagine there is a stacktrace with that? Would you mind sharing it? Cheers,

zahornyak commented 3 months ago
2024-04-03 10:36:15 [    INFO] services.web - No Launch Type defined. Using default: FARGATE
2024-04-03 10:36:16 [    INFO] Service families to process ['web']
Loaded x-vpc vpc vpc /opt/homebrew/Caskroom/miniforge/base/lib/python3.10/site-packages/ecs_composex/vpc
Loaded x-elbv2 elbv2 elbv2 /opt/homebrew/Caskroom/miniforge/base/lib/python3.10/site-packages/ecs_composex/elbv2
2024-04-03 10:36:16 [    INFO] x-elbv2.lb - Adding target web:api
2024-04-03 10:36:16 [    INFO] LB lb only has a unique service. LB will be deployed with the service stack.
2024-04-03 10:36:16 [    INFO] Processing x-vpc
2024-04-03 10:36:22 [    INFO] x-vpc - Found VPC - vpc-0bcfhjsb654ff54aa
2024-04-03 10:36:22 [    INFO] Processing x-elbv2
2024-04-03 10:36:22 [    INFO] x-elbv2.lb - Lookup via Tags
2024-04-03 10:36:25 [    INFO] x-elbv2.lb - Listener 80 found: arn:aws:elasticloadbalancing:us-east-2:1234567890:listener/app/non-prd-alb/80919aa583707f74/b209ccc8aa3a6df6
Traceback (most recent call last):
  File "/opt/homebrew/Caskroom/miniforge/base/bin/ecs-compose-x", line 8, in <module>
    sys.exit(main())
  File "/opt/homebrew/Caskroom/miniforge/base/lib/python3.10/site-packages/ecs_composex/cli.py", line 206, in main
    root_stack = generate_full_template(settings)
  File "/opt/homebrew/Caskroom/miniforge/base/lib/python3.10/site-packages/ecs_composex/ecs_composex.py", line 251, in generate_full_template
    add_x_resources(settings)
  File "/opt/homebrew/Caskroom/miniforge/base/lib/python3.10/site-packages/ecs_composex/ecs_composex.py", line 180, in add_x_resources
    x_stack = module.stack_class(
  File "/opt/homebrew/Caskroom/miniforge/base/lib/python3.10/site-packages/ecs_composex/elbv2/elbv2_stack/__init__.py", line 78, in __init__
    resource.find_lookup_listeners()
  File "/opt/homebrew/Caskroom/miniforge/base/lib/python3.10/site-packages/ecs_composex/elbv2/elbv2_stack/elbv2.py", line 179, in find_lookup_listeners
    listener: LookupListener = LookupListener(self, listener_port, listener_def)
  File "/opt/homebrew/Caskroom/miniforge/base/lib/python3.10/site-packages/ecs_composex/elbv2/elbv2_stack/elbv2_listener/lookup_listener.py", line 82, in __init__
    self.tidy_targets()
  File "/opt/homebrew/Caskroom/miniforge/base/lib/python3.10/site-packages/ecs_composex/elbv2/elbv2_stack/elbv2_listener/lookup_listener.py", line 143, in tidy_targets
    not in [svc["name"] for svc in self.lb.services]
  File "/opt/homebrew/Caskroom/miniforge/base/lib/python3.10/site-packages/ecs_composex/elbv2/elbv2_stack/elbv2_listener/lookup_listener.py", line 143, in <listcomp>
    not in [svc["name"] for svc in self.lb.services]
TypeError: string indices must be integers

I presume that you set 1 for example here? Otherwise, I highly recommend you use the actual listener port number for clarity.

yes, that was an example, I'm using 80 there.

I have an error Could not find 80 in family web when I try to specify family:service:port in service and listener

zahornyak commented 3 months ago

@JohnPreston BTW, how to change the launch type? I do not see any docs about that

JohnPreston commented 3 months ago

@JohnPreston BTW, how to change the launch type? I do not see any docs about that

https://docs.compose-x.io/syntax/compose_x/ecs.details/deploy.html#ecs-compute-platform Will work on a FR #742 as well in a bit. Should that be of interest to you, give a :+1:

JohnPreston commented 3 months ago
2024-04-03 10:36:15 [    INFO] services.web - No Launch Type defined. Using default: FARGATE
2024-04-03 10:36:16 [    INFO] Service families to process ['web']
Loaded x-vpc vpc vpc /opt/homebrew/Caskroom/miniforge/base/lib/python3.10/site-packages/ecs_composex/vpc
Loaded x-elbv2 elbv2 elbv2 /opt/homebrew/Caskroom/miniforge/base/lib/python3.10/site-packages/ecs_composex/elbv2
2024-04-03 10:36:16 [    INFO] x-elbv2.lb - Adding target web:api
2024-04-03 10:36:16 [    INFO] LB lb only has a unique service. LB will be deployed with the service stack.
2024-04-03 10:36:16 [    INFO] Processing x-vpc
2024-04-03 10:36:22 [    INFO] x-vpc - Found VPC - vpc-0bcfhjsb654ff54aa
2024-04-03 10:36:22 [    INFO] Processing x-elbv2
2024-04-03 10:36:22 [    INFO] x-elbv2.lb - Lookup via Tags
2024-04-03 10:36:25 [    INFO] x-elbv2.lb - Listener 80 found: arn:aws:elasticloadbalancing:us-east-2:1234567890:listener/app/non-prd-alb/80919aa583707f74/b209ccc8aa3a6df6
Traceback (most recent call last):
  File "/opt/homebrew/Caskroom/miniforge/base/bin/ecs-compose-x", line 8, in <module>
    sys.exit(main())
  File "/opt/homebrew/Caskroom/miniforge/base/lib/python3.10/site-packages/ecs_composex/cli.py", line 206, in main
    root_stack = generate_full_template(settings)
  File "/opt/homebrew/Caskroom/miniforge/base/lib/python3.10/site-packages/ecs_composex/ecs_composex.py", line 251, in generate_full_template
    add_x_resources(settings)
  File "/opt/homebrew/Caskroom/miniforge/base/lib/python3.10/site-packages/ecs_composex/ecs_composex.py", line 180, in add_x_resources
    x_stack = module.stack_class(
  File "/opt/homebrew/Caskroom/miniforge/base/lib/python3.10/site-packages/ecs_composex/elbv2/elbv2_stack/__init__.py", line 78, in __init__
    resource.find_lookup_listeners()
  File "/opt/homebrew/Caskroom/miniforge/base/lib/python3.10/site-packages/ecs_composex/elbv2/elbv2_stack/elbv2.py", line 179, in find_lookup_listeners
    listener: LookupListener = LookupListener(self, listener_port, listener_def)
  File "/opt/homebrew/Caskroom/miniforge/base/lib/python3.10/site-packages/ecs_composex/elbv2/elbv2_stack/elbv2_listener/lookup_listener.py", line 82, in __init__
    self.tidy_targets()
  File "/opt/homebrew/Caskroom/miniforge/base/lib/python3.10/site-packages/ecs_composex/elbv2/elbv2_stack/elbv2_listener/lookup_listener.py", line 143, in tidy_targets
    not in [svc["name"] for svc in self.lb.services]
  File "/opt/homebrew/Caskroom/miniforge/base/lib/python3.10/site-packages/ecs_composex/elbv2/elbv2_stack/elbv2_listener/lookup_listener.py", line 143, in <listcomp>
    not in [svc["name"] for svc in self.lb.services]
TypeError: string indices must be integers

I presume that you set 1 for example here? Otherwise, I highly recommend you use the actual listener port number for clarity.

yes, that was an example, I'm using 80 there.

I have an error Could not find 80 in family web when I try to specify family:service:port in service and listener

And this is version 1.0.1, right? I am going to add the version to the logs :thinking:

zahornyak commented 3 months ago
2024-04-03 10:36:15 [    INFO] services.web - No Launch Type defined. Using default: FARGATE
2024-04-03 10:36:16 [    INFO] Service families to process ['web']
Loaded x-vpc vpc vpc /opt/homebrew/Caskroom/miniforge/base/lib/python3.10/site-packages/ecs_composex/vpc
Loaded x-elbv2 elbv2 elbv2 /opt/homebrew/Caskroom/miniforge/base/lib/python3.10/site-packages/ecs_composex/elbv2
2024-04-03 10:36:16 [    INFO] x-elbv2.lb - Adding target web:api
2024-04-03 10:36:16 [    INFO] LB lb only has a unique service. LB will be deployed with the service stack.
2024-04-03 10:36:16 [    INFO] Processing x-vpc
2024-04-03 10:36:22 [    INFO] x-vpc - Found VPC - vpc-0bcfhjsb654ff54aa
2024-04-03 10:36:22 [    INFO] Processing x-elbv2
2024-04-03 10:36:22 [    INFO] x-elbv2.lb - Lookup via Tags
2024-04-03 10:36:25 [    INFO] x-elbv2.lb - Listener 80 found: arn:aws:elasticloadbalancing:us-east-2:1234567890:listener/app/non-prd-alb/80919aa583707f74/b209ccc8aa3a6df6
Traceback (most recent call last):
  File "/opt/homebrew/Caskroom/miniforge/base/bin/ecs-compose-x", line 8, in <module>
    sys.exit(main())
  File "/opt/homebrew/Caskroom/miniforge/base/lib/python3.10/site-packages/ecs_composex/cli.py", line 206, in main
    root_stack = generate_full_template(settings)
  File "/opt/homebrew/Caskroom/miniforge/base/lib/python3.10/site-packages/ecs_composex/ecs_composex.py", line 251, in generate_full_template
    add_x_resources(settings)
  File "/opt/homebrew/Caskroom/miniforge/base/lib/python3.10/site-packages/ecs_composex/ecs_composex.py", line 180, in add_x_resources
    x_stack = module.stack_class(
  File "/opt/homebrew/Caskroom/miniforge/base/lib/python3.10/site-packages/ecs_composex/elbv2/elbv2_stack/__init__.py", line 78, in __init__
    resource.find_lookup_listeners()
  File "/opt/homebrew/Caskroom/miniforge/base/lib/python3.10/site-packages/ecs_composex/elbv2/elbv2_stack/elbv2.py", line 179, in find_lookup_listeners
    listener: LookupListener = LookupListener(self, listener_port, listener_def)
  File "/opt/homebrew/Caskroom/miniforge/base/lib/python3.10/site-packages/ecs_composex/elbv2/elbv2_stack/elbv2_listener/lookup_listener.py", line 82, in __init__
    self.tidy_targets()
  File "/opt/homebrew/Caskroom/miniforge/base/lib/python3.10/site-packages/ecs_composex/elbv2/elbv2_stack/elbv2_listener/lookup_listener.py", line 143, in tidy_targets
    not in [svc["name"] for svc in self.lb.services]
  File "/opt/homebrew/Caskroom/miniforge/base/lib/python3.10/site-packages/ecs_composex/elbv2/elbv2_stack/elbv2_listener/lookup_listener.py", line 143, in <listcomp>
    not in [svc["name"] for svc in self.lb.services]
TypeError: string indices must be integers

I presume that you set 1 for example here? Otherwise, I highly recommend you use the actual listener port number for clarity.

yes, that was an example, I'm using 80 there. I have an error Could not find 80 in family web when I try to specify family:service:port in service and listener

And this is version 1.0.1, right? I am going to add the version to the logs 🤔

yes, 1.0.1

JohnPreston commented 3 months ago

Hey @zahornyak Mind trying with the fix that's in #749 ? Clone, get to the branch

cd ecs_composex; git fetch; git checkout fix/elbv2-listener-tidy-function;
python3 -m venv compose_x
source compose_x/bin/activate
pip install .

Then run the command again. I have tested it now with a system that does need it and it's fixed on my end. I did get the same error as you did. Feels like a disconnect between 0.25 and 1.0 and something I haven't tested.

Running a LB 24/7 for no reason costs $ so I haven't gotten to implement lookup testing for it yet.

zahornyak commented 3 months ago

@JohnPreston Sorry, already deployed everything and can't test again. I've created lb instead of lookup on existing, that works for us for now, thanks for your help! BTW, your tool is great and has no great analogs at all