1. Project Overview & Quickstart (openzipkin/zipkin)
File: README.md
zipkin
Zipkin is a distributed tracing system. It helps gather
timing data needed to troubleshoot latency problems in service architectures.
Features include both the collection and lookup of this data.
If you have a trace ID in a log file, you can jump directly to it. Otherwise,
you can query based on attributes such as service, operation name, tags and
duration. Some interesting data will be summarized for you, such as the
percentage of time spent in a service, and whether operations failed.
The Zipkin UI also presents a dependency diagram showing how many traced
requests went through each application. This can be helpful for identifying
aggregate behavior including error paths or calls to deprecated services.
Applicationβs need to be βinstrumentedβ to report trace data to Zipkin. This
usually means configuration of a tracer or instrumentation library. The most
popular ways to report data to Zipkin are via http or Kafka, though many other
options exist, such as Apache ActiveMQ, gRPC, RabbitMQ and Apache Pulsar. The data served to
the UI is stored in-memory, or persistently with a supported backend such as
Apache Cassandra or Elasticsearch.
Quick-start
The quickest way to get started is to fetch the latest released server as a self-contained
executable jar. Note that the Zipkin server requires minimum JRE 17+. For example:
curl -sSL https://zipkin.io/quickstart.sh | bash -s
java -jar zipkin.jarYou can also start Zipkin via Docker.
# Note: this is mirrored as ghcr.io/openzipkin/zipkin
docker run -d -p 9411:9411 openzipkin/zipkinOnce the server is running, you can view traces with the Zipkin UI at http://localhost:9411/zipkin.
If your applications aren't sending traces, yet, configure them with Zipkin instrumentation or try one of our examples.
Check out the zipkin-server documentation for configuration details, or Docker examples for how to use docker-compose.
Zipkin Slim
The slim build of Zipkin is smaller and starts faster. It supports in-memory and Elasticsearch storage, but doesn't support messaging transports like Kafka or RabbitMQ. If these constraints match your needs, you can try slim like below:
Running via Java:
curl -sSL https://zipkin.io/quickstart.sh | bash -s io.zipkin:zipkin-server:LATEST:slim zipkin.jar
java -jar zipkin.jarRunning via Docker:
# Note: this is mirrored as ghcr.io/openzipkin/zipkin-slim
docker run -d -p 9411:9411 openzipkin/zipkin-slimRunning via Homebrew:
brew install zipkin
# to run in foreground
zipkin
# to run in background
brew services start zipkinCore Library
The core library is used by both Zipkin instrumentation and the Zipkin server.
This includes built-in codec for Zipkin's v1 and v2 json formats. A direct dependency on gson
(json library) is avoided by minifying and repackaging classes used. The result is a 155k jar which
won't conflict with any library you use.
Ex.
// All data are recorded against the same endpoint, associated with your service graph
localEndpoint = Endpoint.newBuilder().serviceName("tweetie").ip("192.168.0.1").build()
span = Span.newBuilder()
.traceId("d3d200866a77cc59")
.id("d3d200866a77cc59")
.name("targz")
.localEndpoint(localEndpoint)
.timestamp(epochMicros())
.duration(durationInMicros)
.putTag("compression.level", "9");
// Now, you can encode it as json
bytes = SpanBytesEncoder.JSON_V2.encode(span);Note: The above is just an example, most likely you'll want to use an existing tracing library like Brave
Core Library Requires Java 8+
The minimum Java language level of the core library is 8. This helps support those writing agent
instrumentation. Version 2.x was the last to support Java 6.
Note: zipkin-reporter-brave
does not use this library. So, brave still supports Java 6.
Storage Component
Zipkin includes a StorageComponent, used to store and query spans and
dependency links. This is used by the server and those making collectors, or span reporters.
For this reason, storage components have minimal dependencies, though require Java 17+.
Ex.
// this won't create network connections
storage = ElasticsearchStorage.newBuilder()
.hosts(asList("http://myelastic:9200")).build();
// prepare a call
traceCall = storage.spanStore().getTrace("d3d200866a77cc59");
// execute it synchronously or asynchronously
trace = traceCall.execute();
// clean up any sessions, etc
storage.close();In-Memory
The InMemoryStorage component is packaged in zipkin's core library. It
is neither persistent, nor viable for realistic work loads. Its purpose
is for testing, for example starting a server on your laptop without any
database needed.
Cassandra
The Cassandra component uses Cassandra
3.11.3+ features, but is tested against the latest patch of Cassandra 4.1.
This is the second generation of our Cassandra schema. It stores spans
using UDTs, such that they appear like Zipkin v2 json in cqlsh. It is
designed for scale, and uses a combination of SASI and manually
implemented indexes to make querying larger data more performant.
Note: This store requires a job to aggregate dependency links.
Elasticsearch
The Elasticsearch component uses
Elasticsearch 5+ features, but is tested against Elasticsearch 7-8.x and
OpenSearch 2.x.
It stores spans as Zipkin v2 json so that integration with other tools is
straightforward. To help with scale, this uses a combination of custom
and manually implemented indexing.
Note: This store requires a spark job to aggregate dependency links.
Disabling search
The following API endpoints provide search features, and are enabled by
default. Search primarily allows the trace list screen of the UI operate.
GET /services- Distinct Span.localServiceNameGET /remoteServices?serviceName=X- Distinct Span.remoteServiceName by Span.localServiceNameGET /spans?serviceName=X- Distinct Span.name by Span.localServiceNameGET /autocompleteKeys- Distinct keys of Span.tags subject to configurable whitelistGET /autocompleteValues?key=X- Distinct values of Span.tags by keyGET /traces- Traces matching a query possibly including the above criteria
When search is disabled, traces can only be retrieved by ID
(GET /trace/{traceId}). Disabling search is only viable when there is
an alternative way to find trace IDs, such as logs. Disabling search can
reduce storage costs or increase write throughput.
StorageComponent.Builder.searchEnabled(false) is implied when a zipkin
is run with the env variable SEARCH_ENABLED=false.
Legacy (v1) components
The following components are no longer encouraged, but exist to help aid
transition to supported ones. These are indicated as "v1" as they use
data layouts based on Zipkin's V1 Thrift model, as opposed to the
simpler v2 data model currently used.
MySQL
The MySQL v1 component uses MySQL 5.6+
features, but is tested against MariaDB 10.11.
The schema was designed to be easy to understand and get started with;
it was not designed for performance. Ex spans fields are columns, so
you can perform ad-hoc queries using SQL. However, this component has
known performance issues: queries will eventually take seconds to return
if you put a lot of data into it.
This store does not require a job to aggregate dependency links.
However, running the job will improve performance of dependencies
queries.
Running the server from source
The Zipkin server receives spans via HTTP POST and respond to queries
from its UI. It can also run collectors, such as RabbitMQ or Kafka.
To run the server from the currently checked out source, enter the
following. JDK 17+ is required to compile the source.
# Build the server and also make its dependencies
$ ./mvnw -q --batch-mode -DskipTests --also-make -pl zipkin-server clean install
# Run the server
$ java -jar ./zipkin-server/target/zipkin-server-*exec.jarArtifacts
Server artifacts are under the maven group id io.zipkin
Library artifacts are under the maven group id io.zipkin.zipkin2
Library Releases
Releases are at Maven Central
Library Snapshots
Snapshots are uploaded to Sonatype after
commits to master.
Docker Images
Released versions of zipkin-server are published to Docker Hub as openzipkin/zipkin and GitHub
Container Registry as ghcr.io/openzipkin/zipkin. See docker for details.
Helm Charts
Helm charts are available via helm repo add zipkin https://zipkin.io/zipkin-helm.
See zipkin-helm for details.
Javadocs
https://zipkin.io/zipkin contains versioned folders with JavaDocs published on each (non-PR) build, as well
as releases.
File: benchmarks/README.md
zipkin-benchmarks
This module includes JMH
benchmarks for zipkin. You can use these to measure overhead.
Running the benchmark
From the project directory, run this to build the benchmarks:
$ ./mvnw install -pl benchmarks -am -Dmaven.test.skip.exec=trueand the following to run them:
$ java -jar benchmarks/target/benchmarks.jarFile: build-bin/README.md
Test and Deploy scripts
This is a Maven+Docker project, which uses standard conventions for test and deploy with some
exceptions.
On [../zipkin-lens]:
- [maybe_install_npm] is used to build on an unsupported node.js architecture.
- [maven_go_offline] additionally seeds the NPM cache
On test:
- [test], used by [../.github/workflows/test.yml] runs Maven unit and integration tests.
- Its "test" job skips docker, as they are run in parallel in "test_docker"
- [../.github/workflows/readme_test.yml] tests build commands in [../zipkin-server] and [../docker]
- zipkin, zipkin-lens and zipkin-slim Docker builds use
RELEASE_FROM_MAVEN_BUILD=true- this avoids invoking Maven builds from within Docker, which are costly and fragile
- Docker tests run in sequence to avoid queueing delays, which take longer than builds themselves.
- zipkin, zipkin-lens and zipkin-slim Docker builds use
On deploy:
- [deploy], used by [../.github/workflows/deploy.yml] publishes jars and Docker images.
- [javadoc_to_gh_pages] pushes Javadoc to the gh-pages branch on MAJOR.MINOR.PATCH branch, but not master.
- gh-pages is addressable via https://zipkin.io/zipkin/
- Besides production Docker images, this project includes [../docker/test-images].
- [docker_push] pushes test-images, but only to ghcr.io
Build Overview
build-bin holds portable scripts used in CI to test and deploy the project.
The scripts here are portable. They do not include any CI provider-specific logic or ENV variables.
This helps test.yml (GitHub Actions) and alternatives contain nearly the same contents, even if
certain OpenZipkin projects need slight adjustments here. Portability has proven necessary, as
OpenZipkin has had to transition CI providers many times due to feature and quota constraints.
These scripts serve a second purpose, which is to facilitate manual releases, which has also
happened many times due usually to service outages of CI providers. While tempting to use
CI-provider specific tools, doing so can easily create a dependency where no one knows how to
release anymore. Do not use provider-specific mechanisms to implement release flow. Instead,
automate triggering of the scripts here.
The only scripts that should be modified per project are in the base directory. Those in
subdirectories, such as docker, should not vary project to project except accident of
version drift. Intentional changes in subdirectories should be relevant and tested on multiple
projects to ensure they can be blindly copy/pasted.
Conversely, the files in the base directory are project specific entry-points for test and deploy
actions and are entirely appropriate to vary per project. Here's an overview:
Lint
Lint makes sure that documentation and workflows are in-tact. CI providers should be configured to
run lint on pull requests or pushes to the master branch, notably when the tag is blank. Linters
should only run on documentation-only commits or those who affect workflow files. Linters must not
depend on authenticated resources, as running lint can leak credentials.
- configure_lint - Ensures linters are installed
- lint - Runs the linters
We minimally check the following:
- markdown-link-check on our Markdown content.
- we maintain mlc_config.json for exceptions
- yamllint on our GitHub Actions Workflow YAML.
- occasionally need line length exceptions via
# yamllint disable-line rule:line-length
- occasionally need line length exceptions via
Example GitHub Actions setup
A simplest GitHub Actions lint.yml runs linters after configuring them, but only on relevant event
conditions. The name lint.yml and job lint allows easy references to status badges and parity of
the scripts it uses.
The on: section obviates job creation and resource usage for irrelevant events. Notably, GitHub
Actions includes the ability to skip documentation-only jobs.
Here's a partial lint.yml including only the aspects mentioned above.
---
on: # yamllint disable-line rule:truthy
push: # non-tagged pushes to master
branches:
- master
tags-ignore:
- '*'
paths:
- '**/*.md'
- '.github/workflows/*.yml'
- './build-bin/*lint'
- ./build-bin/mlc_config.json
pull_request: # pull requests targeted at the master branch.
branches:
- master
paths:
- '**/*.md'
- '.github/workflows/*.yml'
- './build-bin/*lint'
- ./build-bin/mlc_config.json
jobs:
lint:
name: Lint
runs-on: ubuntu-24.04 # newest available distribution, aka noble
# skip commits made by the release plugin
if: "!contains(github.event.head_commit.message, 'maven-release-plugin')"
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Lint
run: |
build-bin/configure_lint
build-bin/lintTest
Test builds and runs any tests of the project, including integration tests. CI providers should be
configured to run tests on pull requests or pushes to the master branch, notably when the tag is
blank. Tests should not run on documentation-only commits. Tests must not depend on authenticated
resources, as running tests can leak credentials.
- configure_test - Sets up build environment for tests.
- test - Builds and runs tests for this project.
Example GitHub Actions setup
A simplest GitHub Actions test.yml runs tests after configuring them, but only on relevant event
conditions. The name test.yml and job test allows easy references to status badges and parity of
the scripts it uses.
The on: section obviates job creation and resource usage for irrelevant events. Notably, GitHub
Actions includes the ability to skip documentation-only jobs.
Here's a partial test.yml including only the aspects mentioned above.
on: # yamllint disable-line rule:truthy
push: # non-tagged pushes to master
branches:
- master
tags-ignore:
- '*'
paths-ignore:
- '**/*.md'
- './build-bin/*lint'
- ./build-bin/mlc_config.json
pull_request: # pull requests targeted at the master branch.
branches:
- master
paths-ignore:
- '**/*.md'
- './build-bin/*lint'
- ./build-bin/mlc_config.json
jobs:
test:
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Test
run: |
build-bin/configure_test
build-bin/testDeploy
Deploy builds and pushes artifacts to a remote repository for master and release commits on it. CI
providers deploy pushes to master on when the tag is blank, but not on documentation-only commits.
Releases should deploy on version tags (ex /^[0-9]+\.[0-9]+\.[0-9]+/), without consideration of if
the commit is documentation only or not.
- configure_deploy - Sets up environment and logs in.
- deploy - deploys the project, with arg1 being "master" or a release commit like "1.2.3"
Example GitHub Actions setup
A simplest GitHub Actions deploy.yml deploys after logging in, but only on relevant event
conditions. The name deploy.yml and job deploy allows easy references to status badges and
parity of the scripts it uses.
The on: section obviates job creation and resource usage for irrelevant events. GitHub Actions
cannot implement "master, except documentation only-commits" in the same file. Hence, deployments of
master will happen even on README change.
Here's a partial deploy.yml including only the aspects mentioned above. Notice env variables are
explicitly defined and on.tags is a glob pattern.
on: # yamllint disable-line rule:truthy
push:
branches:
- master
# Don't deploy tags because the same commit for MAJOR.MINOR.PATCH is also
# on master: Redundant deployment of a release version will fail uploading.
tags-ignore:
- '*'
jobs:
deploy:
runs-on: ubuntu-24.04 # newest available distribution, aka noble
steps:
- name: Checkout Repository
uses: actions/checkout@v4
with:
fetch-depth: 1 # only needed to get the sha label
- name: Deploy
env:
GH_USER: ${{ secrets.GH_USER }}
GH_TOKEN: ${{ secrets.GH_TOKEN }}
run: | # GITHUB_REF = refs/heads/master or refs/tags/MAJOR.MINOR.PATCH
build-bin/configure_deploy &&
build-bin/deploy $(echo ${GITHUB_REF} | cut -d/ -f 3)File: docker/examples/README.md
Zipkin Docker Examples
This project is configured to run docker containers using
docker-compose.
To start the default docker compose configuration, run:
# To use the last released version of zipkin
$ docker compose up
# To use the last built version of zipkin
$ TAG=master docker compose upView the web UI at $(docker ip):9411. Traces are stored in memory.
To see specific traces in the UI, select "zipkin-server" in the dropdown and
then click the "Find Traces" button.
ActiveMQ
You can collect traces from ActiveMQ in addition to HTTP, using thedocker-compose-activemq.yml file. This configuration starts zipkin and zipkin-activemq in their
own containers.
To add ActiveMQ configuration, run:
$ docker compose -f docker-compose-activemq.yml upThen configure the ActiveMQ sender
using a brokerUrl value of failover:tcp://localhost:61616 or a non-local hostname if in docker.
Cassandra
You can store traces in Cassandra instead of memory, using thedocker-compose-cassandra.yml file. This configuration starts zipkin, zipkin-cassandra andzipkin-dependencies (cron job) in their own containers.
To start the Cassandra-backed configuration, run:
$ docker compose -f docker-compose-cassandra.yml upThe zipkin-dependencies container is a scheduled task that runs every hour.
If you want to see the dependency graph before then, you can run it manually
in another terminal like so:
$ docker compose -f docker-compose-cassandra.yml run --rm --no-deps --entrypoint start-zipkin-dependencies dependenciesElasticsearch
You can store traces in Elasticsearch instead of memory,
using the docker-compose-elasticsearch.yml file. This configuration starts zipkin,zipkin-elasticsearch and zipkin-dependencies (cron job) in their own containers.
To start the Elasticsearch-backed configuration, run:
$ docker compose -f docker-compose-elasticsearch.yml upThe zipkin-dependencies container is a scheduled task that runs every hour.
If you want to see the dependency graph before then, you can run it manually
in another terminal like so:
$ docker compose -f docker-compose-elasticsearch.yml run --rm --no-deps --entrypoint start-zipkin-dependencies dependenciesKafka
You can collect traces from Kafka in addition to HTTP, using thedocker-compose-kafka.yml file. This configuration starts zipkin and zipkin-kafka in their
own containers.
To add Kafka configuration, run:
$ docker compose -f docker-compose-kafka.yml upThen configure the Kafka sender using a bootstrapServers value of host.docker.internal:9092 if your application is inside the same docker network or localhost:19092 if not, but running on the same host.
In other words, if you are running a sample application on your laptop, you would use localhost:19092 bootstrap server to send spans to the Kafka broker running in Docker.
Docker machine and Kafka
If you are using Docker machine, adjust KAFKA_ADVERTISED_HOST_NAME in docker-compose-kafka.yml
and the bootstrapServers configuration of the kafka sender to match your Docker host IP (ex. 192.168.99.100:19092).
MySQL
You can store traces in MySQL instead of memory, using thedocker-compose-mysql.yml file. This configuration starts zipkin, zipkin-mysql andzipkin-dependencies (cron job) in their own containers.
To start the MySQL-backed configuration, run:
$ docker compose -f docker-compose-mysql.yml upRabbitMQ
You can collect traces from RabbitMQ in addition to HTTP, using thedocker-compose-rabbitmq.yml file. This configuration starts zipkin and zipkin-rabbitmq in their
own containers.
To add RabbitMQ configuration, run:
$ docker compose -f docker-compose-rabbitmq.yml upThen configure the RabbitMQ sender
using a host value of localhost or a non-local hostname if in docker.
Pulsar
You can collect traces from Pulsar in addition to HTTP, using thedocker-compose-pulsar.yml file. This configuration starts zipkin and zipkin-pulsar in their
own containers.
To add Pulsar configuration, run:
$ docker compose -f docker-compose-pulsar.yml upEureka
You can register Zipkin for service discovery in Eureka
using the docker-compose-eureka.yml file. This configuration starts zipkin and zipkin-eureka
in their own containers.
When zipkin starts, it registers its endpoint into eureka. Then, the two example services
discover zipkin's endpoint from eureka and use it to send spans.
To try this out, run:
$ docker compose -f docker-compose.yml -f docker-compose-eureka.yml upExample
The docker compose configuration can be extended to host an example application
using the docker-compose-example.yml file. That file employs docker compose overrides
to add a "frontend" and "backend" service.
To add the example configuration, run:
$ docker compose -f docker-compose.yml -f docker-compose-example.yml upOnce the services start, open http://localhost:8081/
- This calls the backend (http://localhost:9000/api) and shows its result: a formatted date.
Afterward, you can view traces that went through the backend via http://localhost:9411/zipkin?serviceName=backend
UI
The docker compose configuration can be extended to host the UI on port 80
using the docker-compose-ui.yml file. That file employs
docker compose overrides
to add an NGINX container and relevant settings.
To start the NGINX configuration, run:
$ docker compose -f docker-compose.yml -f docker-compose-ui.yml upThis container doubles as a skeleton for creating proxy configuration around
Zipkin like authentication, dealing with CORS with zipkin-js apps, or
terminating SSL.
If you want to run the zipkin-ui standalone against a remote zipkin server, you
need to set ZIPKIN_BASE_URL accordingly:
$ docker run -d -p 80:80 \
-e ZIPKIN_BASE_URL=http://myfavoritezipkin:9411 \
openzipkin/zipkin-uiUI Proxy
The docker compose configuration can be extended to proxy the UI on port 80
using the docker-compose-uiproxy.yml file. That file employs
docker compose overrides to add an NGINX container and relevant settings.
To start the NGINX configuration, run:
$ docker compose -f docker-compose.yml -f docker-compose-uiproxy.yml upThis container helps verify the ZIPKIN_UI_BASEPATH variable by setting it to
"/admin/zipkin". This means when the compose configuration is up, you can
access Zipkin UI at http://localhost/admin/zipkin/
Prometheus
Zipkin comes with a built-in Prometheus metric exporter. Thedocker-compose-prometheus.yml file starts Prometheus configured to scrape
Zipkin, exposes it on port 9090. You can open $DOCKER_HOST_IP:9090 and
start exploring metrics (available on the /prometheus endpoint of Zipkin).
docker-compose-prometheus.yml also starts a Grafana with authentication
disabled, exposing it on port 3000. On startup it's configured with the
Prometheus instance started by docker-compose as a data source, and imports
the dashboard published at https://grafana.com/dashboards/1598. This means that,
after running docker-compose ... -f docker-compose-prometheus.yml up, you
can open $DOCKER_IP:3000/dashboard/db/zipkin-prometheus and play around with
the dashboard.
File: docker/test-images/zipkin-uiproxy/README.md
zipkin-uiproxy Docker image
The zipkin-uiproxy testing image proxies the Zipkin UI with NGINX.
Besides norms defined in docker-alpine, this accepts the
following environment variables:
ZIPKIN_UI_BASEPATH: The path this proxy serves the UI under. Defaults to /zipkinZIPKIN_BASE_URL: The proxied zipkin base URL. Defaults to http://zipkin:9411
To build openzipkin/zipkin-ui:test, from the top-level of the repository, run:
$ DOCKER_FILE=docker/test-images/zipkin-uiproxy/Dockerfile build-bin/docker/docker_build openzipkin/zipkin-uiproxy:testFile: docker/test-images/zipkin-ui/README.md
zipkin-ui Docker image
The zipkin-ui testing image contains the static parts of the Zipkin UI served directly with NGINX.
Besides norms defined in docker-alpine, this accepts the
following environment variables:
ZIPKIN_BASE_URL: The proxied zipkin base URL. Defaults to http://zipkin:9411
To build openzipkin/zipkin-ui:test, from the top-level of the repository, run:
$ DOCKER_FILE=docker/test-images/zipkin-ui/Dockerfile build-bin/docker/docker_build openzipkin/zipkin-ui:testFile: docker/test-images/zipkin-rabbitmq/README.md
zipkin-rabbitmq Docker image
The zipkin-rabbitmq testing image runs rabbitmq-server for the
RabbitMQ collector integration.
For convenience, this includes the "guest" user and a default queue named
"zipkin". To add more queues, exec amqp-declare-queue in a running container.
To build openzipkin/zipkin-rabbitmq:test, from the top-level of the repository, run:
$ DOCKER_FILE=docker/test-images/zipkin-rabbitmq/Dockerfile build-bin/docker/docker_build openzipkin/zipkin-rabbitmq:testFile: docker/test-images/zipkin-pulsar/README.md
zipkin-pulsar Docker image
The zipkin-pulsar testing image runs Pulsar for Pulsar collector integration.
To build openzipkin/zipkin-pulsar:test, from the top-level of the repository, run:
$ DOCKER_FILE=docker/test-images/zipkin-pulsar/Dockerfile build-bin/docker/docker_build openzipkin/zipkin-pulsar:testYou can use the env variable PULSAR_LOG_ROOT_LEVEL to change the log level for Pulsar. Defaults to "WARN".
File: docker/test-images/zipkin-opensearch2/README.md
zipkin-opensearch2 Docker image
The zipkin-opensearch2 testing image runs OpenSearch 2.x for Elasticsearch storage
integration.
To build openzipkin/zipkin-opensearch2:test, from the top-level of the repository, run:
$ DOCKER_FILE=docker/test-images/zipkin-opensearch2/Dockerfile build-bin/docker/docker_build openzipkin/zipkin-opensearch2:testYou can use the env variable OPENSEARCH_JAVA_OPTS to change settings such as heap size for OpenSearch.
Host setup
OpenSearch is strict
about virtual memory. You will need to adjust accordingly (especially if you notice OpenSearch crash!)
# If docker is running on your host machine, adjust the kernel setting directly
$ sudo sysctl -w vm.max_map_count=262144
# If using docker-machine/Docker Toolbox/Boot2Docker, remotely adjust the same
$ docker-machine ssh default "sudo sysctl -w vm.max_map_count=262144"
# If using colima, it is similar as well
$ colima ssh "sudo sysctl -w vm.max_map_count=262144"File: docker/test-images/zipkin-mysql/README.md
zipkin-mysql Docker image
The zipkin-mysql testing image runs MySQL 10.x initialized with Zipkin's schema for
MySQL storage integration.
To build openzipkin/zipkin-mysql:test, from the top-level of the repository, run:
$ DOCKER_FILE=docker/test-images/zipkin-mysql/Dockerfile build-bin/docker/docker_build openzipkin/zipkin-mysql:testWhen running with docker-machine, you can connect like so:
$ mysql -h $(docker-machine ip) -u zipkin -pzipkin -D zipkin2. Official Technical Reference & Guides (openzipkin/openzipkin.github.io)
File: README.md
openzipkin.github.io
This repository contains the source code for the Zipkin documentation site
http://zipkin.io. It's the
organization page
for openzipkin, hosted using
GitHub pages and Jekyll.
This means that everything on the master branch is immediately and
automatically published.
It uses the static site generator Jekyll. Jekyll is
implemented in Ruby and requires Ruby
version >= 2.7.
Contributing
Improvements to the documentation are more than welcome. This section tries to
get you up to speed on how to run the site locally and make changes. Just like
the documentation, this meta-documentation also welcomes all improvements. If
you can, you should use OSX or Linux; Jekyll is not very well supported on
Windows.
If you've done this kind of thing before
You may wish to use rbenv to ensure your Ruby and Bundler versions are
consistent before proceeding.
- Fork, branch, clone
bundlejekyll serve- Make changes, commit, push
- Open a pull-request
Preparing your environment
Install Ruby
The official documentation at
https://www.ruby-lang.org/en/documentation/installation/ describes the
procedure for all major operating systems.System-level dependencies
Nokogiri, one of the components used by Jekyll,
requires some system-level libraries to be in place before installation of
Jekyll can begin. Things should generally work out of the box, but keep in
mind that if Jekyll installation fails referencing Nokogiri, then the
Installing Nokogiri
document most likely has what you need.Clone the repository
textgit clone https://github.com/openzipkin/openzipkin.github.io.gitInstall Jekyll and friends
GitHub quite considerately provides the exact list of packages that are used
to generate the site on GitHub Pages, which means we can use the exact same
packages when running the site locally. This minimizes differences between
what you see locally, and what you'll see in production.Gemfile
defines the packages to be installed using the list provided by GitHub (andGemfile.lockmakes sure we all have the same versions
locally). To install these packages:textcd openzipkin.github.io bundleRun the site
You're now all set! The following command starts Jekyll, and makes the site
available at http://localhost:4000. It'll also pick
up any changes you make locally, and regenerate the site, so you can review
your changes live without having to restart Jekyll.textbundle exec jekyll serve
Finding your way around the repository
Next up is making some changes to the site. To do that, you'll need to have a
basic understanding of how the repository is structured.
Content for all the pages lives in the pages directory. This makes it
very clear where you need to look when making changes to the website text; it's
clearly separated from all the scaffolding around the actual content. The only
exception is the home page, index.md. It's in the root of the
repository for purely technical reasons (GitHub Pages can only serve the root
document from the root of the repository, and doesn't allow running any Jekyll
plugins).
The rest of the repository contains scaffolding; here's a list to give you a
basic idea of what's what:
_datacontains lists of things that are rendered into various
parts of the page. For instance the list of tracers and instrumentation
is defined here in a structured way._includescontains HTML snippets that are shared by some or
all pages._layoutscontains the basic HTML shared by all pages - and
references snippets in_includes. At the time of writing, all pages use thepagelayout, and I don't foresee new layouts becoming actively used._sasscontains style-sheets implemented inSass.publiccontains static content that's directly served to browsers as-is..editorconfigcontains
EditorConfig configuration that makes sure
editors supporting EditorConfig format files in this repository in the same
way (think spaces vs tabs)CNAMEtells GitHub pages that this site should be served at
http://zipkin.io instead of
http://openzipkin.zipkin.io. For details on
how, see
[https://help.github.com/articles/using-a-custom-domain-with-github-pages/](Using
a custom domain with GitHub Pages)GemfileandGemfile.lockdescribe the Ruby
packages used for building and serving this site; see the documentation of
Bundler for more details._config.ymlcontains configuration options used by Jekyll
when generating the site.
Some finer points
There are a few things to keep an eye out for while making changes to the site.
- For links to work correctly both locally, on forks, and in production, we
need to include{{ site.github.url }}at the beginning of URLs. For
example, a link to the Quickstart guide looks like this:{{ site.github.url }}/pages/quickstart. This is expanded by Jekyll to the correct value based
on where it's running. More documentation is available
here - A link to each page appears in the side-bar. The links are ordered based on a
custom valueweightassigned to each page. By default each page has a
weight of 100 - the default is defined in_config.yml. This can be
overridden in each page, seeindex.mdfor an example. Pages
with lower weight come first in the list. Pages with the same weight are
sorted however Jekyll sees fit - probably alphabetically.
* This is implemented by custom logic for in
_includes/sidebar.html. As we add more
content, we may want to add more structure to the side-bar, and we may
need to re-think this approach. Worst case, we can manage the side-bar
contents manually.
Creating a pull-request
Once you've made your changes, you'll want to create a pull-request, so that the
changes can be merged into the master branch ofopenzipkin/openzipkin.github.io, and so published for the betterment of all.
This section describes the steps for getting there, assuming you've followed the
instructions so far.
Fork this repository
Go to
openzipkin/openzipkin.github.io,
and click the "Fork" button. Or just
click here.Tell git about your fork
We're going to call your fork
origin, and the originalopenzipkin
repositoryupstream. The following commands tellgitto make the
appropriate changes:textgit remote rename origin upstream git remote add origin [email protected]:$USER/openzipkin.github.io git fetch upstreamCreate a branch, commit and push your changes
textgit checkout -b my-awesome-changes git commit -m 'Short, useful description of my changes' git pushOpen a pull-request
Open https://github.com/openzipkin/openzipkin.github.io. You should see a bar
above the list of files that says you've recently pushed to your branch, with
a green button on the right to open a pull request. Click it; add text to
text fields and click buttons as appropriate. See
https://help.github.com/articles/using-pull-requests/
for detailed instructions.
Pulling changes
When you come back to the project later, you'll want to make sure you have all
the recent changes downloaded before making any further changes. Note: the
following commands throw away any and all changes you have locally. If that's
not desired, refer to the documentation of your git client.
git checkout master
git fetch upstream
git reset --hard upstream/master
git pushYou'll also want to make sure you have all the required Ruby packages, at
exactly the required versions:
bundleYou are now ready to start a new branch and add more awesome to the
documentation.
File: build-bin/README.md
Test and Deploy scripts
This is a Jekyll project, which only includes the [test] command as files are served as-is with
GitHub Pages.
Unlike code-based projects, we test documentation-only commits: this is literally a website!
Build Overview
build-bin holds portable scripts used in CI to test and deploy the project.
The scripts here are portable. They do not include any CI provider-specific logic or ENV variables.
This helps .travis.yml and test.yml (GitHub Actions) contain nearly the same contents, even if
certain OpenZipkin projects need slight adjustments here. Portability has proven necessary, as
OpenZipkin has had to transition CI providers many times due to feature and quota constraints.
These scripts serve a second purpose, which is to facilitate manual releases, which has also
happened many times due usually to service outages of CI providers. While tempting to use
CI-provider specific tools, doing so can easily create a dependency where no one knows how to
release anymore. Do not use provider-specific mechanisms to implement release flow. Instead,
automate triggering of the scripts here.
The only scripts that should be modified per project are in the base directory. Those in sub
directories, such as [docker], should not vary project to project except accident of version drift.
Intentional changes in sub directories should be relevant and tested on multiple projects to ensure
they can be blindly copy/pasted.
Conversely, the files in the base directory are project specific entry-points for test and deploy
actions and are entirely appropriate to vary per project. Here's an overview:
Test
Test builds and runs any tests of the project, including integration tests. CI providers should be
configured to run tests on pull requests or pushes to the master branch, notably when the tag is
blank. Tests should not run on documentation-only commits. Tests must not depend on authenticated
resources, as running tests can leak credentials. Git checkouts should include the full history so
that license headers or other git analysis can take place.
- [configure_test] - Sets up build environment for tests.
- [test] - Builds and runs tests for this project.
Example GitHub Actions setup
A simplest GitHub Actions test.yml runs tests after configuring them, but only on relevant event
conditions. The name test.yml and job test allows easy references to status badges and parity of
the scripts it uses.
The on: section obviates job creation and resource usage for irrelevant events. Notably, GitHub
Actions includes the ability to skip documentation-only jobs.
Combine [configure_test] and [test] into the same run: when configure_test primes file system
cache.
Here's a partial test.yml including only the aspects mentioned above.
on:
push:
tags: ''
branches: master
paths-ignore: '**/*.md'
pull_request:
branches: master
paths-ignore: '**/*.md'
jobs:
test:
steps:
- name: Checkout Repository
uses: actions/checkout@v2
with:
fetch-depth: 0 # full git history
- name: Test
run: build-bin/configure_test && build-bin/testExample Travis setup
.travis.yml is a monolithic configuration file broken into stages, of which the default is "test".
A simplest Travis test job configures tests in install and runs them as script, but only on
relevant event conditions.
The if: section obviates job creation and resource usage for irrelevant events. Travis does not
support file conditions. A before_install step to skip documentation-only commits will likely
complete in less than a minute (10 credit cost).
Here's a partial .travis.yml including only the aspects mentioned above.
git:
depth: false # full git history for license check, and doc-only skipping
jobs:
include:
- stage: test
if: branch = master AND tag IS blank AND type IN (push, pull_request)
name: Run unit and integration tests
before_install: |
if [ -n "${TRAVIS_COMMIT_RANGE}" ] && ! git diff --name-only "${TRAVIS_COMMIT_RANGE}" -- | grep -qv '\.md$'; then
echo "Stopping job as changes only affect documentation (ex. README.md)"
travis_terminate 0
fi
install: ./build-bin/configure_test
script: ./build-bin/testDeploy
Deploy builds and pushes artifacts to a remote repository for master and release commits on it. CI
providers deploy pushes to master on when the tag is blank, but not on documentation-only commits.
Releases should deploy on version tags (ex /^[0-9]+\.[0-9]+\.[0-9]+/), without consideration of if
the commit is documentation only or not.
- [configure_deploy] - Sets up environment and logs in, assuming [configure_test] was not called.
- [deploy] - deploys the project, with arg0 being "master" or a release commit like "1.2.3"
Example GitHub Actions setup
A simplest GitHub Actions deploy.yml deploys after logging in, but only on relevant event
conditions. The name deploy.yml and job deploy allows easy references to status badges and
parity of the scripts it uses.
The on: section obviates job creation and resource usage for irrelevant events. GitHub Actions
cannot implement "master, except documentation only-commits" in the same file. Hence, deployments of
master will happen even on README change.
Combine [configure_deploy] and [deploy] into the same run: when configure_deploy primes file
system cache.
Here's a partial deploy.yml including only the aspects mentioned above. Notice env variables are
explicitly defined and on.tags is a glob pattern.
on:
push:
tags: '[0-9]+.[0-9]+.[0-9]+**' # Ex. 8.272.10 or 15.0.1_p9
branches: master
jobs:
deploy:
steps:
- name: Checkout Repository
uses: actions/checkout@v2
with:
fetch-depth: 1 # only needed to get the sha label
- name: Deploy
env:
GH_USER: ${{ secrets.GH_USER }}
GH_TOKEN: ${{ secrets.GH_TOKEN }}
run: | # GITHUB_REF will be refs/heads/master or refs/tags/N.M.L
build-bin/configure_deploy &&
build-bin/deploy $(echo ${GITHUB_REF} | cut -d/ -f 3)Example Travis setup
.travis.yml is a monolithic configuration file broken into stages. This means test and deploy
are in the same file. A simplest Travis deploy stage has two jobs: one for master pushes and
another for version tags. These jobs are controlled by event conditions.
The if: section obviates job creation and resource usage for irrelevant events. Travis does not
support file conditions. A before_install step to skip documentation-only commits will likely
complete in less than a minute (10 credit cost).
As billing is by the minute, it is most cost effective to combine test and deploy on master push.
Here's a partial .travis.yml including only the aspects mentioned above. Notice YAML anchors work
in Travis and tag =~ condition is a regular
expression.
git:
depth: false # full git history for license check, and doc-only skipping
_terminate_if_only_docs: &terminate_if_only_docs |
if [ -n "${TRAVIS_COMMIT_RANGE}" ] && ! git diff --name-only "${TRAVIS_COMMIT_RANGE}" -- | grep -qv '\.md$'; then
echo "Stopping job as changes only affect documentation (ex. README.md)"
travis_terminate 0
fi
jobs:
include:
- stage: test
if: branch = master AND tag IS blank AND type IN (push, pull_request)
before_install: *terminate_if_only_docs
install: |
if [ "${TRAVIS_SECURE_ENV_VARS}" = "true" ] && [ "${TRAVIS_PULL_REQUEST}" = "false" ]; then
export SHOULD_DEPLOY=true
./build-bin/configure_deploy
else
export SHOULD_DEPLOY=false
./build-bin/configure_test
fi
script:
- ./build-bin/test || travis_terminate 1
- if [ "${SHOULD_DEPLOY}" != "true" ]; then travis_terminate 0; fi
- travis_wait ./build-bin/deploy master
- stage: deploy
# Ex. 8.272.10 or 15.0.1_p9
if: tag =~ /^[0-9]+\.[0-9]+\.[0-9]+/ AND type = push AND env(GH_TOKEN) IS present
install: ./build-bin/configure_deploy
script: ./build-bin/deploy ${TRAVIS_TAG}