Skip to content

Attach to externally-started LS container#190

Open
carole-lavillonniere wants to merge 5 commits intomainfrom
attach-to-running
Open

Attach to externally-started LS container#190
carole-lavillonniere wants to merge 5 commits intomainfrom
attach-to-running

Conversation

@carole-lavillonniere
Copy link
Copy Markdown
Collaborator

@carole-lavillonniere carole-lavillonniere commented Apr 14, 2026

Summary

  • lstk start now attaches to an already-running LocalStack container instead of failing. It fails if the port is different than the configured one.
  • lstk stop locates and stops an externally-started container
  • lstk status returns status of an externally-started container if any

Towards DRG-553

Started outside of lstk (eg CLI v1, or locally built and ran in docker):

running-with-clliv1

Already running on a different port:

running-other-port

Status command shows details about the version and container name:

running-local-build

Possible improvement:

Add interactivity and let user decide if the existing container should be picked up or replaced

@carole-lavillonniere carole-lavillonniere changed the title feat: attach to externally-started LocalStack containers Attach to externally-started LS container Apr 14, 2026
@carole-lavillonniere carole-lavillonniere changed the base branch from otel-tracing to main April 15, 2026 12:46
When `lstk start` is run and a LocalStack container is already running
(started outside lstk, e.g. via docker run or Compose), lstk now attaches
to it rather than failing or trying to start a duplicate.

Detection uses two complementary strategies:
- Docker API: `FindRunningByImage` filters by image repo + bound host port
  via the `ancestor` filter, returning the running container regardless of
  its name or tag
- HTTP fallback: if the Docker filter misses it (different image name,
  mid-restart), `/_localstack/info` is probed on the configured port

Behaviour on attach:
- Same version as config: "LocalStack is already running" (exit 0)
- Different version: warning with both versions shown (exit 0)
- Port in use by non-LocalStack process: existing error (exit 1)

`lstk stop` also gains the same fallback: if no container matches the
configured name, `FindRunningByImage` is used to locate and stop the
externally-started container. `ContainerRemove` conflict/not-found errors
(e.g. container started with --rm) are now silently ignored since removal
was already in progress.
@carole-lavillonniere carole-lavillonniere marked this pull request as ready for review April 15, 2026 12:47
Copy link
Copy Markdown

@claude claude Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.

Tip: disable this comment in your organization's Code Review settings.

@gtsiolis
Copy link
Copy Markdown
Member

Looking at this now! 👀

Copy link
Copy Markdown
Member

@gtsiolis gtsiolis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice one, @carole-lavillonniere! 💯

Added a first round of comments in some relevant lines of code, let me know if something does not make sense. 🙏

Comment thread internal/container/running.go
Comment thread internal/container/start.go Outdated
Comment thread internal/runtime/docker.go
Comment thread internal/container/start.go Outdated
Comment thread internal/container/start.go
Comment thread test/integration/start_test.go
@carole-lavillonniere
Copy link
Copy Markdown
Collaborator Author

Nice one, @carole-lavillonniere! 💯

Added a first round of comments in some relevant lines of code, let me know if something does not make sense. 🙏

Thanks for testing extensively @gtsiolis
I addressed your comments and would appreciate another round of testing.

Copy link
Copy Markdown
Contributor

@anisaoshafi anisaoshafi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was easy to follow the changes; tested and LGTM 🚀
Good decision to simplify start/stop commands by dismissing the tag/port and informing the user accordingly!

Comment thread test/integration/start_test.go Outdated
Copy link
Copy Markdown
Member

@gtsiolis gtsiolis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left some more comments, @carole-lavillonniere! What do you think?

if found.BoundPort != c.Port {
output.EmitError(sink, output.ErrorEvent{
Title: fmt.Sprintf("LocalStack is already running on port %s", found.BoundPort),
Summary: fmt.Sprintf("Config expects port %s. Only one instance can run at a time.", c.Port),
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thought: We previously didn't have this restriction.

Only one instance can run at a time.

I'd expect to be able to spin up more than one instance as long as the port is different. This is how it works now, you can set GATEWAY_LISTEN="0.0.0.0:4567" and start a second instance side by side. See also relevant feedback.

}
if conflictPort, err := ports.CheckAvailable(extraSpecs...); err != nil {
output.EmitError(sink, output.ErrorEvent{
Title: fmt.Sprintf("Port %s is already in use", conflictPort),
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

praise: This works as expected, even if it's another service running! 💯

if conflictPort, err := ports.CheckAvailable(extraSpecs...); err != nil {
output.EmitError(sink, output.ErrorEvent{
Title: fmt.Sprintf("Port %s is already in use", conflictPort),
Summary: "LocalStack requires this port. Another instance may be running.",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thought: This might not be true when another service is using the port you configured. Could show this line only when port 4566 is configured?

# When configured to use port 4566
✗ Port 4566 already in use
> LocalStack may already be running.

# When configured to use port any other port other than 4566
✗ Port 4568 already in use

if found != nil {
if found.BoundPort != c.Port {
output.EmitError(sink, output.ErrorEvent{
Title: fmt.Sprintf("LocalStack is already running on port %s", found.BoundPort),
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: If you are running two instances, on port 4566 and port 4567, this message now is partially true as it captures only one instance. Since we're doing plain port check for now, I'd highlight the port conflict and only assume LS is running when the config is using 4566.

emitEmulatorStartError(ctx, tel, c, telemetry.ErrCodePortConflict, fmt.Sprintf("running on port %s, configured port %s", found.BoundPort, c.Port))
return nil, output.NewSilentError(fmt.Errorf("LocalStack already running on port %s", found.BoundPort))
}
output.EmitInfo(sink, "LocalStack is already running")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: If you are running another service on 4566 or the same port, this message is quite misleading. ⚠️

Another service on port 4566 Trying to start LS on port 4566
Image Screenshot 2026-04-23 at 11 02 49

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants