Initialization Hooks
Lifecycle Stages and Hooks
Section titled “Lifecycle Stages and Hooks”LocalStack has four well-known lifecycle phases or stages:
BOOT
: the container is running but the LocalStack runtime has not been startedSTART
: the Python process is running and the LocalStack runtime is startingREADY
: LocalStack is ready to serve requestsSHUTDOWN
: LocalStack is shutting down
You can hook into each of these lifecycle phases using custom shell or Python scripts.
Each lifecycle phase has its own directory in /etc/localstack/init
.
You can mount individual files, stage directories, or the entire init directory from your host into the container.
Directoryetc
Directorylocalstack
Directoryinit
- boot.d executed in the container before localstack starts
- ready.d executed when localstack becomes ready
- shutdown.d executed when localstack shuts down
- start.d executed when localstack starts up
In these directories, you can put either executable shell scripts or Python programs, which will be executed from within a Python process.
All except boot.d
will be run in the same Python interpreter as LocalStack, which gives additional ways of configuring/extending LocalStack.
You can also use subdirectories to organize your init scripts.
Currently, known script extensions are .sh
and .py
.
Additionally, with the installation of the localstack-extension-terraform-init
extension, .tf
files can also be supported.
Shell scripts have to be executable, and have to have a shebang (usually #!/bin/bash
).
A script can be in one of four states: UNKNOWN
, RUNNING
, SUCCESSFUL
, ERROR
.
Scripts are by default in the UNKNOWN
state once they have been discovered.
The remaining states should be self-explanatory.
Execution Order and Script Failures
Section titled “Execution Order and Script Failures”Scripts are sorted and executed in alphanumerical order.
If you use subdirectories, scripts in parent folders are executed first, and then the directories are traversed in alphabetical order, depth first.
If an init script fails, the remaining scripts will still be executed in order.
A script is considered in ERROR
state if it is a shell script and returns with a non-zero exit code, or if a Python script raises an exception during its execution.
Status Endpoint
Section titled “Status Endpoint”There is an additional endpoint at localhost:4566/_localstack/init
which returns the state of the initialization procedure.
Boot scripts (scripts placed in boot.d
) are currently always in the UNKNOWN
state, since they are executed outside the LocalStack process and we don’t know whether they have been successfully executed or not.
curl -s localhost:4566/_localstack/init | jq .
{ "completed": { "BOOT": false, "START": true, "READY": true, "SHUTDOWN": false }, "scripts": [ { "stage": "BOOT", "name": "booting.sh", "state": "UNKNOWN" }, { "stage": "READY", "name": "pre_seed.py", "state": "SUCCESSFUL" } ]}
Querying Stages
Section titled “Querying Stages”You can also query a specific stage at localhost:4566/_localstack/init/<stage>
:
curl -s localhost:4566/_localstack/init/ready | jq .
{ "completed": true, "scripts": [ { "stage": "READY", "name": "pre_seed.py", "state": "SUCCESSFUL" } ]}
To check whether a given stage has been completed you can now run, for example:
curl -s localhost:4566/_localstack/init/ready | jq .completed
which returns either true
or false
.
Example
Section titled “Example”A common use case for init hooks is pre-seeding LocalStack with custom state. For example if you want to have a certain S3 bucket or DynamoDB table created when starting LocalStack, init hooks can be very useful.
To execute aws cli commands when LocalStack becomes ready,
simply create a script init-aws.sh
and mount it into /etc/localstack/init/ready.d/
.
Make sure the script is executable: run chmod +x init-aws.sh
on the file first.
You can use anything available inside the container, including awslocal
:
#!/bin/bash
export AWS_ACCESS_KEY_ID=000000000000 AWS_SECRET_ACCESS_KEY=000000000000
awslocal s3 mb s3://my-bucketawslocal sqs create-queue --queue-name my-queue
Start Localstack:
services: localstack: container_name: "${LOCALSTACK_DOCKER_NAME:-localstack-main}" image: localstack/localstack ports: - "127.0.0.1:4566:4566" environment: - DEBUG=1 volumes: - "/path/to/init-aws.sh:/etc/localstack/init/ready.d/init-aws.sh" # ready hook - "${LOCALSTACK_VOLUME_DIR:-./volume}:/var/lib/localstack" - "/var/run/docker.sock:/var/run/docker.sock"
# DOCKER_FLAGS are additional parameters to the `docker run` command of localstack start
DOCKER_FLAGS='-v /path/to/init-aws.sh:/etc/localstack/init/ready.d/init-aws.sh' localstack start
Another use for init hooks can be seen when adding custom TLS certificates to LocalStack.
Terraform Files as Init Hooks
Section titled “Terraform Files as Init Hooks”Running Terraform configuration files as init hooks requires the installation of a special extension. For more information on how to manage LocalStack extensions, please refer to the dedicated documentation page, and for more details on running init hooks in development mode, you can check out the extension repository description.
Start LocalStack with EXTENSION_AUTO_INSTALL="localstack-extension-terraform-init"
.
Mount a main.tf
file into /etc/localstack/init/ready.d
When LocalStack starts up, it will install the extension, which in turn installs Terraform and tflocal
into the container.
If one of the init stage directories contain a main.tf
file, the extension will run tflocal init
and tflocal apply
on that directory.
resource "aws_s3_bucket" "example" {bucket = "my-tf-test-bucket"
tags = {Name = "My bucket"Environment = "Dev" }}
Start LocalStack Pro with mounted main.tf
:
services: localstack: container_name: "localstack-main" image: localstack/localstack-pro # required for Pro ports: - "127.0.0.1:4566:4566" # LocalStack Gateway environment:# Activate LocalStack Pro: https://docs.localstack.cloud/getting-started/auth-token/ - LOCALSTACK_AUTH_TOKEN=${LOCALSTACK_AUTH_TOKEN:?} - EXTENSION_AUTO_INSTALL=localstack-extension-terraform-init volumes:# you could also place your main.tf in `./ready.d` and set "./ready.d:/etc/localstack/init/ready.d" - "./main.tf:/etc/localstack/init/ready.d/main.tf" - "./volume:/var/lib/localstack" - "/var/run/docker.sock:/var/run/docker.sock"
localstack start \ -e EXTENSION_AUTO_INSTALL="localstack-extension-terraform-init" \ -v ./main.tf:/etc/localstack/init/ready.d/main.tf
You can wait for LocalStack to complete the startup process, and then print the created S3 bucket:
localstack wait && awslocal s3 ls
The logs should show something like:
2024-06-26T20:36:19.946 INFO --- [ady_monitor)] l.extension : Applying terraform project from file /etc/localstack/init/ready.d/main.tf2024-06-26T20:36:19.946 DEBUG --- [ady_monitor)] localstack.utils.run : Executing command: ['tflocal', '-chdir=/etc/localstack/init/ready.d', 'init', '-input=false']2024-06-26T20:36:26.864 DEBUG --- [ady_monitor)] localstack.utils.run : Executing command: ['tflocal', '-chdir=/etc/localstack/init/ready.d', 'apply', '-auto-approve']
For a more complex demo project, on how to use Terraform init hooks for your testing environments, you can check out this example in the Tutorials section.
Troubleshooting
Section titled “Troubleshooting”If you are having issues with your initialization hooks not being executed, please perform the following checks:
- Do the scripts have a known file extensions (
.sh
or.py
)?- If not, rename the files to the matching file extension.
- Is the script file configured to use LF endings instead of CRLF endings?
- If not, switch the file to LF mode as it is utilized in the Unix environment within a container.
- Is the script marked as executable?
- If not, set the executable flag on the file (
chmod +x ...
).
- If not, set the executable flag on the file (
- If it’s a shell script, does it have a shebang (e.g.,
#!/bin/bash
) as the first line in the file?- If not, add the shebang header (usually
#!/bin/bash
) on top of your script file.
- If not, add the shebang header (usually
- Is the script being listed in the logs when running LocalStack with
DEBUG=1
?-
The detected scripts are logged like this:
Terminal window ...Init scripts discovered: {BOOT: [], START: [], READY: [Script(path='/etc/localstack/init/ready.d/setup.sh', stage=READY, state=UNKNOWN)], SHUTDOWN: []}...Running READY script /etc/localstack/init/ready.d/setup.sh... -
If your script does not show up in the list of discovered init scripts, please check your Docker volume mount. Most likely the scripts are not properly mounted into the Docker container.
-
- Are resources not being created?
- Ensure that AWS credentials are set, e.g. through
AWS_ACCESS_KEY_ID
andAWS_SECRET_ACCESS_KEY
environment variables.
- Ensure that AWS credentials are set, e.g. through