diff --git a/Dockerfile.fpm b/Dockerfile.fpm new file mode 100644 index 0000000..1876871 --- /dev/null +++ b/Dockerfile.fpm @@ -0,0 +1,13 @@ +FROM php:8.3-fpm + +RUN apt-get update && apt-get install -y unzip libzip-dev && rm -rf /var/cache/apt/* +RUN curl -sSL https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions -o - | sh -s \ + opentelemetry-php/ext-opentelemetry@main opcache zip grpc intl calendar pdo_mysql mysqli +RUN curl -sS https://getcomposer.org/installer | php && mv composer.phar /usr/local/bin/composer +RUN composer self-update +RUN usermod -a -G www-data root +RUN mkdir -p /var/www/html +RUN chown -R www-data:www-data /var/www/html +WORKDIR /var/www/html/ + +# TODO: check-me diff --git a/Dockerfile.nginx b/Dockerfile.nginx new file mode 100644 index 0000000..a2ed8c1 --- /dev/null +++ b/Dockerfile.nginx @@ -0,0 +1,5 @@ +FROM nginx:1.25.3-alpine +#RUN mkdir -p /var/www/html/public +COPY public /var/www/html/public +COPY docker/nginx/default.conf /etc/nginx/conf.d/default.conf +EXPOSE 80 diff --git a/Dockerfile.static b/Dockerfile.static new file mode 100644 index 0000000..e69de29 diff --git a/develop.sh b/develop.sh new file mode 100755 index 0000000..8998fe4 --- /dev/null +++ b/develop.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env sh + +set -ex + +docker compose build + +# composer +docker compose run -it php-fpm composer install + +# database +docker compose run -it php-fpm /var/www/html/artisan migrate +docker compose run -it php-fpm /var/www/html/artisan db:seed CountrySeeder + +# laravel Swagger +docker compose run -it php-fpm /var/www/html/artisan l5-swagger:generate + +# run containers (and build again) +if [ "$NO_EXECUTE" != "1" ]; then + docker compose up --build +fi diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..85d9923 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,118 @@ +version: '3.9' + +services: + nginx: + build: + context: . + dockerfile: ./Dockerfile.nginx + ports: + - '8000:80' + volumes: + - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf + links: + - php-fpm + php-fpm: + build: + context: . + dockerfile: ./Dockerfile.fpm + volumes: + - ./:/var/www/html/ + environment: + - OTEL_LOG_LEVEL=debug + - OTEL_TRACES_EXPORTER=otlp + - OTEL_METRICS_EXPORTER=otlp + - OTEL_LOGS_EXPORTER=otlp + - OTEL_PHP_AUTOLOAD_ENABLED=true + - OTEL_PHP_TRACES_PROCESSOR=simple + - OTEL_PHP_LOG_DESTINATION=stderr + - OTEL_EXPORTER_OTLP_PROTOCOL=grpc + - OTEL_EXPORTER_OTLP_ENDPOINT=http://otelcol:4317 + - DB_CONNECTION=mysql + - DB_URL=mysql://laravel:laravel@mariadb:3306/workingdays + links: + - otelcol + - mariadb + depends_on: + mariadb: + condition: service_healthy + dns: + - 8.8.8.8 + mariadb: + image: mariadb:10.6 + environment: + - MYSQL_ROOT_PASSWORD=laravel + - MYSQL_DATABASE=workingdays + - MYSQL_USER=laravel + - MYSQL_PASSWORD=laravel + healthcheck: + test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"] + start_period: 10s + interval: 10s + timeout: 5s + retries: 3 + + # ----------------- telemetry + + + tempo: + image: grafana/tempo:latest + command: [ "-config.file=/etc/tempo.yaml" ] + volumes: + - ./docker/telemetry/tempo.yaml:/etc/tempo.yaml + - ./.tempo:/tmp/tempo + loki: + image: grafana/loki:2.9.2 + ports: + - "3100:3100" + command: -config.file=/etc/loki.yaml + volumes: + - ./.loki:/loki + - ./docker/telemetry/loki.yaml:/etc/loki.yaml + + promtail: + image: grafana/promtail:2.9.2 + command: -config.file=/etc/promtail/config.yaml + volumes: + - ./docker/telemetry/promtail.yaml:/etc/promtail/config.yaml + links: + - prometheus + + prometheus: + image: prom/prometheus:latest + command: + - --config.file=/etc/prometheus.yaml + - --web.enable-remote-write-receiver + - --enable-feature=exemplar-storage + volumes: + - ./docker/telemetry/prometheus.yaml:/etc/prometheus.yaml + ports: + - "9090:9090" + + grafana: + image: grafana/grafana:10.1.1 + volumes: + - ./docker/telemetry/grafana-datasources.yaml:/etc/grafana/provisioning/datasources/datasources.yaml + environment: + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin + - GF_AUTH_DISABLE_LOGIN_FORM=true + - GF_FEATURE_TOGGLES_ENABLE=traceqlEditor + ports: + - "3000:3000" + + otelcol: + image: otel/opentelemetry-collector-contrib:latest + deploy: + resources: + limits: + memory: 125M + restart: unless-stopped + command: [ "--config=/etc/otelcol-config.yaml" ] + volumes: + - ./docker/telemetry/otelcol-config.yaml:/etc/otelcol-config.yaml + depends_on: + - loki + - tempo + links: + - loki + - tempo diff --git a/docker/nginx/default.conf b/docker/nginx/default.conf new file mode 100644 index 0000000..c6fc6c0 --- /dev/null +++ b/docker/nginx/default.conf @@ -0,0 +1,19 @@ +server { + index index.php index.html; + server_name symfony_example_app; + error_log stderr debug; + access_log stderr; + listen 80; + root /var/www/html/public; + + location / { + try_files $uri /index.php$is_args$args; + } + + location ~ ^/.+\.php(/|$) { + fastcgi_pass php-fpm:9000; + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + } +} + diff --git a/docker/telemetry/grafana-datasources.yaml b/docker/telemetry/grafana-datasources.yaml new file mode 100644 index 0000000..7a7fabd --- /dev/null +++ b/docker/telemetry/grafana-datasources.yaml @@ -0,0 +1,43 @@ +apiVersion: 1 + +datasources: +- name: Prometheus + type: prometheus + uid: prometheus + access: proxy + orgId: 1 + url: http://prometheus:9090 + basicAuth: false + isDefault: false + version: 1 + editable: false + jsonData: + httpMethod: GET +- name: Tempo + type: tempo + access: proxy + orgId: 1 + url: http://tempo:3200 + basicAuth: false + isDefault: true + version: 1 + editable: false + apiVersion: 1 + uid: tempo + jsonData: + httpMethod: GET + serviceMap: + datasourceUid: prometheus +- name: Loki + type: loki + access: proxy + orgId: 1 + url: http://loki:3100 + basicAuth: false + isDefault: false + version: 1 + editable: false + apiVersion: 1 + uid: loki + jsonData: + httpMethod: GET diff --git a/docker/telemetry/loki.yaml b/docker/telemetry/loki.yaml new file mode 100644 index 0000000..107ec0c --- /dev/null +++ b/docker/telemetry/loki.yaml @@ -0,0 +1,37 @@ +auth_enabled: false + +server: + http_listen_port: 3100 + grpc_listen_port: 9096 + +common: + instance_addr: 127.0.0.1 + path_prefix: /tmp/loki + storage: + filesystem: + chunks_directory: /tmp/loki/chunks + rules_directory: /tmp/loki/rules + replication_factor: 1 + ring: + kvstore: + store: inmemory + +query_range: + results_cache: + cache: + embedded_cache: + enabled: true + max_size_mb: 100 + +schema_config: + configs: + - from: 2020-10-24 + store: tsdb + object_store: filesystem + schema: v12 + index: + prefix: index_ + period: 24h + +ruler: + alertmanager_url: http://localhost:9093 diff --git a/docker/telemetry/otelcol-config.yaml b/docker/telemetry/otelcol-config.yaml new file mode 100644 index 0000000..ebbe007 --- /dev/null +++ b/docker/telemetry/otelcol-config.yaml @@ -0,0 +1,68 @@ +receivers: + loki: + protocols: + grpc: + use_incoming_timestamp: true + otlp: + protocols: + grpc: +processors: + attributes: + actions: + - action: insert + key: loki.attribute.labels + value: context, code.filepath, code.namespace, code.function, code.lineno, http.request.method, http.request.body.size, url.full, url.scheme, url.path, http.route, http.response.status_code + - action: insert + from_attribute: context + key: context + - action: insert + from_attribute: code.namespace + key: code.namespace + - action: insert + from_attribute: code.function + key: code.function + - action: insert + from_attribute: code.lineno + key: code.lineno + - action: insert + from_attribute: http.request.method + key: http.request.method + - action: insert + from_attribute: http.request.body.size + key: http.request.body.size + - action: insert + from_attribute: http.response.status_code + key: http.response.status_code + - action: insert + from_attribute: url.full + key: url.full + - action: insert + from_attribute: url.scheme + key: url.scheme + - action: insert + from_attribute: url.path + key: url.path + - action: insert + from_attribute: http.route + key: http.route + - action: insert + key: loki.format + value: raw +exporters: + loki: + endpoint: http://loki:3100/loki/api/v1/push + otlp: + endpoint: tempo:4317 + tls: + insecure: true + logging: + verbosity: Detailed +service: + pipelines: + logs: + receivers: [otlp] + processors: [attributes] + exporters: [logging,loki] + traces: + receivers: [otlp] + exporters: [logging,otlp] diff --git a/docker/telemetry/prometheus.yaml b/docker/telemetry/prometheus.yaml new file mode 100644 index 0000000..2ac6859 --- /dev/null +++ b/docker/telemetry/prometheus.yaml @@ -0,0 +1,11 @@ +global: + scrape_interval: 15s + evaluation_interval: 15s + +scrape_configs: + - job_name: 'prometheus' + static_configs: + - targets: [ 'localhost:9090' ] + - job_name: 'tempo' + static_configs: + - targets: [ 'tempo:3200' ] \ No newline at end of file diff --git a/docker/telemetry/promtail.yaml b/docker/telemetry/promtail.yaml new file mode 100644 index 0000000..b37b278 --- /dev/null +++ b/docker/telemetry/promtail.yaml @@ -0,0 +1,2 @@ +clients: + - url: http://otelcol:3500/loki/api/v1/push \ No newline at end of file diff --git a/docker/telemetry/tempo.yaml b/docker/telemetry/tempo.yaml new file mode 100644 index 0000000..55fc23a --- /dev/null +++ b/docker/telemetry/tempo.yaml @@ -0,0 +1,73 @@ +server: + http_listen_port: 3200 + +query_frontend: + search: + duration_slo: 5s + throughput_bytes_slo: 1.073741824e+09 + trace_by_id: + duration_slo: 5s + +distributor: + receivers: # this configuration will listen on all ports and protocols that tempo is capable of. + jaeger: # the receives all come from the OpenTelemetry collector. more configuration information can + protocols: # be found there: https://github.com/open-telemetry/opentelemetry-collector/tree/main/receiver + thrift_http: # + grpc: # for a production deployment you should only enable the receivers you need! + thrift_binary: + thrift_compact: + zipkin: + otlp: + protocols: + http: + grpc: + opencensus: + +ingester: + max_block_duration: 5m # cut the headblock when this much time passes. this is being set for demo purposes and should probably be left alone normally + + + +metrics_generator: + processor: + span_metrics: + dimensions: [http.status_code, http.method] + dimension_mappings: + - name: http_status_code + source_labels: [http_status_code] + - name: http_method + source_labels: [http_method] + enable_target_info: true + registry: + external_labels: + source: tempo + cluster: docker-compose + storage: + path: /tmp/tempo/generator/wal + remote_write: + - url: http://prometheus:9090/api/v1/write + send_exemplars: true + +storage: + trace: + backend: local # backend configuration to use + wal: + path: /tmp/tempo/wal # where to store the the wal locally + local: + path: /tmp/tempo/blocks + +overrides: + defaults: + metrics_generator: + + processors: [service-graphs, span-metrics] # enables metrics generator + global: + # Maximum size of a single trace in bytes. A value of 0 disables the size + # check. + # This limit is used in 3 places: + # - During search, traces will be skipped when they exceed this threshold. + # - During ingestion, traces that exceed this threshold will be refused. + # - During compaction, traces that exceed this threshold will be partially dropped. + # During ingestion, exceeding the threshold results in errors like + # TRACE_TOO_LARGE: max size of trace (5000000) exceeded while adding 387 bytes + max_bytes_per_trace: 20000000 \ No newline at end of file