akondas/symfony-consul-bundle
Install the Bundle
composer require akondas/symfony-consul-bundle
Add to config/bundles.php:
return [
// ...
Akondas\ConsulBundle\ConsulBundle::class => ['all' => true],
];
Configure in config/packages/consul.yaml
consul:
service:
name: 'your-service-name' # e.g., 'api-service'
host: '%env(CONSUL_HOST)%' # Defaults to 'localhost'
port: '%env(int:CONSUL_PORT)%' # Defaults to 8000
client:
base_uri: 'http://%env(CONSUL_SERVER)%:8500' # Defaults to 'http://127.0.0.1:8500'
Enable Routing (Optional)
Add to config/routes.yaml:
consul_bundle:
resource: '@ConsulBundle/Resources/config/routing.yml'
First Registration Run the registration command:
php bin/console consul:register
Verify in Consul UI (http://<consul-server>:8500/ui) under Services.
consul.yaml with your service name (name: 'api-service').consul:register during deployment (e.g., in a post-deploy hook).api-service.service.consul) or HTTP API to resolve the service dynamically in your app.KernelEvents::TERMINATE).
// src/EventListener/ConsulRegistrationListener.php
namespace App\EventListener;
use Akondas\ConsulBundle\Command\RegisterCommand;
use Symfony\Component\HttpKernel\Event\TerminateEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class ConsulRegistrationListener implements EventSubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [
KernelEvents::TERMINATE => 'registerService',
];
}
public function registerService(TerminateEvent $event): void
{
$command = new RegisterCommand();
$command->run(new \Symfony\Component\Console\Input\ArrayInput([]), new \Symfony\Component\Console\Output\BufferedOutput());
}
}
Pros: No manual CLI calls needed; service registers on app startup.
Cons: Requires Consul client to be reachable at boot./health endpoint).
Configure in consul.yaml:
consul:
service:
checks:
- name: 'HTTP API Health Check'
script: 'curl -s http://localhost:8000/health | grep -q "ok"'
interval: '10s'
Use Case: Validate business logic (e.g., DB connectivity) beyond HTTP status.%env% for dynamic Consul server URLs.
consul:
client:
base_uri: 'http://%env(CONSUL_SERVER)%:8500'
Deployment Example:
CONSUL_SERVER=localhostCONSUL_SERVER=consul.prod.example.com
Tooling: Integrate with Ansible/Terraform to set CONSUL_SERVER via environment variables.// src/EventListener/ConsulDeregistrationListener.php
use Akondas\ConsulBundle\Command\DeregisterCommand;
class ConsulDeregistrationListener implements EventSubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [
KernelEvents::TERMINATE => 'deregisterService',
];
}
public function deregisterService(TerminateEvent $event): void
{
$command = new DeregisterCommand();
$command->run(new \Symfony\Component\Console\Input\ArrayInput([]), new \Symfony\Component\Console\Output\BufferedOutput());
}
}
Why: Prevents "zombie" services in Consul after container crashes.consul:register in a Docker entrypoint script or Kubernetes postStart hook.
Example (Dockerfile):
COPY docker-entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
ENTRYPOINT ["docker-entrypoint.sh"]
docker-entrypoint.sh:
#!/bin/sh
php bin/console consul:register
exec "$@"
Kubernetes:
lifecycle:
postStart:
exec:
command: ["/bin/sh", "-c", "php bin/console consul:register"]
base_uri is unreachable, the bundle silently fails.
Debug:
php bin/console debug:consul-check
Fix: Use a retry mechanism (e.g., Guzzle middleware) or wrap the command in a try-catch:
try {
$command->run($input, $output);
} catch (\Exception $e) {
// Log and continue (e.g., for non-critical services)
$this->logger->warning('Consul registration failed', ['error' => $e->getMessage()]);
}
0.0.0.0 (e.g., Docker), use host: '0.0.0.0' in consul.yaml.
Example:
consul:
service:
host: '0.0.0.0' # Critical for Docker/K8s
port: 8000
Why: Consul advertises the service as http://0.0.0.0:8000, which works for internal service mesh traffic.consul:
service:
checks:
- name: 'HTTPS Health Check'
http: 'https://localhost:8000/health'
interval: '10s'
tls_skip_verify: true # For self-signed certs
api-service-{{HOSTNAME}}).tags to distinguish environments:
consul:
service:
tags: ['env=prod', 'version=v1.2']
debug:consul-check to validate checks before registration:
php bin/console debug:consul-check
Output Example:
[OK] HTTP check for http://localhost:8000/health passed (status: 200)
[WARN] Script check failed: "curl: (7) Failed to connect to localhost port 8000: Connection refused"
ConsulService class.
Example:
// src/Consul/CustomConsulService.php
namespace App\Consul;
use Akondas\ConsulBundle\Service\ConsulService as BaseConsulService;
class CustomConsulService extends BaseConsulService
{
public function getServiceDefinition(): array
{
$definition = parent::getServiceDefinition();
$definition['meta'] = ['team' => 'backend
How can I help you explore Laravel packages today?