rileydakota / valheim-ecs-fargate-cdk

AWS CDK/Cloudformation to deploy a Valheim Server using ECS Fargate!
78 stars 24 forks source link

What is the best way to suspend/resume server? #8

Open hiragram opened 3 years ago

hiragram commented 3 years ago

Hello! Thank you for your great job. I'm enjoying survival life with my friends.

I have a small experience around AWS, but new to ECS, Fargate, and CDK. I want to know the best way to stop servers to avoid being charged, and resume when we start playing again.

If you told me the instruction, I can add it to readme.

rileydakota commented 3 years ago

Hi there @hiragram - thanks for reaching out. So you have a couple of options:

  1. Manually modify the desired number of tasks for the Fargate Service from 1 to 0 (will get old fast, but here for reference: image (CLI command is also an option for this as well - but same pain)

  2. Add Cloudwatch Event Triggers to change the number of desired tasks automatically based on a cron expression: https://docs.aws.amazon.com/cdk/api/latest/docs/aws-ecs-readme.html#integration-with-cloudwatch-events (EG - could have rules that change the number of tasks to 0 on weeknights after 2am and set it back to 1 after 12pm?)

Number 2 is probably the best option - just need to figure out a good way to add it without making it too specific to one person.

rileydakota commented 3 years ago

I am working on adding #2 in some form (maybe a documented set of examples addable to the code?) - but would also be very open to a PR :)

sdredsoxfan commented 3 years ago

I am working on adding #2 in some form (maybe a documented set of examples addable to the code?) - but would also be very open to a PR :)

I'd actually be quite curious to know how you'd solve the problem of turning the server back on automatically. AFAIK, there isn't a good way to detect this since the server wouldn't be discoverable while off.

rileydakota commented 3 years ago

@sdredsoxfan you are correct - sadly there is no way to handle it in that manner - but we can "Schedule" the server via CloudWatch Event Rules. For example - if you know your group only plays during 4pm-1am EST during weekdays, you could schedule the task to power down during the off hours and save a good bit of money. This is all dependent on this being acceptable to the end user however. Will work for some, but not others.

sdredsoxfan commented 3 years ago

Makes sense. I think a temporal solution is really the only thing feasible! I was discussing with the people I play with about it. Not sure it would work well for me personally because one of them likes to get some farming in throughout the day.

sdredsoxfan commented 3 years ago

You could possibly set up an API Gateway that users can hit which uses a Lambda to fire up the server and allow auth'd users to turn on the server when they want to play and then let the auto shut down mechanism fire.

hiragram commented 3 years ago

@rileydakota Thank you! I could resume/restart server perfectly!

rileydakota commented 3 years ago

@hiragram happy to hear it! @sdredsoxfan I was actually thinking of adding a discord/slack bot for a little bit of chatsops type management (think /valheim-aws stop). Just have to rely on people to shut it off (or could just have an auto power off mechanism too)

DaveB93 commented 3 years ago

Just a question / comment on this. When the server restarts it has a different IP. I guess you could also put a command on the api gateway to get the server IP ? alternately you could set up route 53 to point to the servers dns.

or is there an auto-assigned dns for fargateClusters ?

rileydakota commented 3 years ago

Hi @DaveB93 - I think to get a static IP you would need to utilize an ELB, and then map a route53 Hosted Zone to the ELB AFAIK. I am planning to add this to the template soon, will probably add a toggle to enable it/disable it as it will add additional cost to the solution

DaveB93 commented 3 years ago

re: Using Cloudwatch Event rules, I wasn't able to figure out how to use that to set the desired capacity for the service to 0 ( to stop things ) or to use it to set the task to stop. instead I ended up using AWS application autoscaling on the service to change the desired capacity.

First you need to register a scalable target

aws application-autoscaling register-scalable-target --service-namespace ecs --resource-id service/ValheimServerAwsCdkStack-fargateCluster#####/ValheimServerAwsCdkStack-valheimService##### --scalable-dimension ecs:service:DesiredCount --min-capacity 0 --max-capacity 1

Then you just set up your rules to stop and start.

aws application-autoscaling put-scheduled-action --service-namespace ecs --resource-id service/ValheimServerAwsCdkStack-fargateCluster####/ValheimServerAwsCdkStack-valheimService#### --schedule "cron(0 0 * * ? *)" --timezone America/Vancouver --scheduled-action-name stopAtMidnight --scalable-dimension ecs:service:DesiredCount --scalable-target-action MinCapacity=0,MaxCapacity=0

to list your existing rules you can aws application-autoscaling describe-scheduled-actions --service-namespace ecs

Note: it's possible to set --scalable-target-action adjust just the Min or Max capacity, if you're trying to shut the server down, you will have to adjust both Min and Max to 0 in order to get it to work, or you will get the following error in your Event logs: Message: Failed to set max capacity to 0. Reason: Maximum capacity cannot be less than minimum capacity Cause: scheduled action name stopAtMidnight was triggered

https://docs.aws.amazon.com/autoscaling/application/userguide/examples-scheduled-actions.html https://docs.aws.amazon.com/cli/latest/reference/application-autoscaling/register-scalable-target.html https://docs.aws.amazon.com/cli/latest/reference/application-autoscaling/put-scheduled-action.html

it does look like there's cdk hooks for that https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-applicationautoscaling.ScalableTarget.html but I'm not that familiar with the cdk, so not ready to add them via that yet.

DaveB93 commented 3 years ago

I've gotten some lambda functions set up that allow your friends to start/stop the server and see the server IP and if it's running. I currently have them here https://github.com/DaveB93/lambda-ecs-fargate-updownstatus in a very messy state. I will see about working with the CDK to automate the setup of them a bit more, and then possibly integrate them with this script.

DaveB93 commented 3 years ago

Okay I've converted my deploy to use the CDK. It probably wouldn't be too hard to merge it in with your repo, but in order to compile the nodejs lambdas it ends up needing docker installed. ( it might work by just installing esbuild, but I didn't play with that. ) I haven't done conditionals in the CDK yet, and I haven't looked up how to pass values from one service to another, so not sure how into merging them I am at this point.

I also have done the bare minimum of authentication. It feels like it want to be frontended by Cognito, but I didn't find a sample cognito website ( with only a tiny bit of searching. ) I might come back to it, but for now it's probably good enough for me and my friends.

PAHelper2 commented 3 years ago

Can someone provide a cli example to set the instance count to 1 or 0?

rileydakota commented 3 years ago

@DaveB93 if you want to create a bare bones PR we can collaborate on combining the code

DaveB93 commented 3 years ago

@PAHelper2

Can someone provide a cli example to set the instance count to 1 or 0?

aws ecs update-service --cluster ValheimServerAwsCdkStack-fargateClusterXXX-eccXXXX --service ValheimServerAwsCdkStack-valheimServiceXXXX-ojXXXXX --desired-count 0

DaveB93 commented 3 years ago

Hey @rileydakota I have a PR, but I need permission from my work to post it. ( thing in my employment contract. )

DaveB93 commented 3 years ago

sorry for the delay on the PR. work took a while to approve it.

skeeters1 commented 3 years ago

Help request

Love this. Thank you. Just getting started and I am struggling to trigger the start/stop via API gateway in the most basic way. The status function works easily from my browser: https://MY_ARN.execute-api.eu-west-2.amazonaws.com/prod/serverstatus returns a "running" status and IP address as expected

But I can't authenticate to the start/stop: https://MY_ARN.execute-api.eu-west-2.amazonaws.com/prod/startstop?MYPASSWORD returns not authenticated

I think I just can't get the URL syntax right and not good enough with lambda to debug it. Would someone mind giving an example snippet please?

Agree an EIP option would be helpful as would Discord integration. Also a "start server unless already running" function which any team member could run. Thanks!

DaveB93 commented 3 years ago

Help request

Love this. Thank you. Just getting started and I am struggling to trigger the start/stop via API gateway in the most basic way. The status function works easily from my browser: https://MY_ARN.execute-api.eu-west-2.amazonaws.com/prod/serverstatus returns a "running" status and IP address as expected

But I can't authenticate to the start/stop: https://MY_ARN.execute-api.eu-west-2.amazonaws.com/prod/startstop?MYPASSWORD returns not authenticated

I think I just can't get the URL syntax right and not good enough with lambda to debug it. Would someone mind giving an example snippet please?

@skeeters1 my apologies, I have my github email going to an account I don't really check. are you still looking for help with this?

looking at your URI, you need key=MYPASSWORD

e.g. https://MY_ARN.execute-api.eu-west-2.amazonaws.com/prod/startstop?key=MYPASSWORD

Agree an EIP option would be helpful as would Discord integration. Also a "start server unless already running" function which any team member could run. Thanks!

the startstop works exactly as this. if they run start as https://MY_ARN.execute-api.eu-west-2.amazonaws.com/prod/startstop?key=MYPASSWORD

and stop as

https://MY_ARN.execute-api.eu-west-2.amazonaws.com/prod/startstop?key=MYPASSWORD@desiredCount=0

Mood93 commented 3 years ago

the startstop works exactly as this. if they run start as https://MY_ARN.execute-api.eu-west-2.amazonaws.com/prod/startstop?key=MYPASSWORD

and stop as

https://MY_ARN.execute-api.eu-west-2.amazonaws.com/prod/startstop?key=MYPASSWORD@desiredCount=0

Correction: the @ before desiredCount should be an &