skipper
An HTTP router and reverse proxy for service composition, including use cases like Kubernetes Ingress
Top Related Projects
The Cloud Native Application Proxy
Connect, secure, control, and observe services.
Cloud-native high-performance edge/middle/service proxy
🦍 The Cloud-Native API Gateway and AI Gateway.
The official NGINX Open Source repository.
HAProxy Load Balancer's development branch (mirror of git.haproxy.org)
Quick Overview
Skipper is an HTTP router and reverse proxy for service composition. It acts as a custom, programmable HTTP router that can be used as a Kubernetes Ingress controller. Skipper provides advanced traffic routing capabilities, request and response modifications, and various middleware functionalities.
Pros
- Highly customizable with a rich set of built-in filters and predicates
- Supports dynamic routing updates without restarts
- Integrates well with Kubernetes as an Ingress controller
- Offers advanced traffic management features like rate limiting, circuit breaking, and blue-green deployments
Cons
- Steeper learning curve compared to simpler reverse proxies
- Configuration can become complex for advanced use cases
- Limited community support compared to more popular alternatives like Nginx or Traefik
- Documentation could be more comprehensive for some advanced features
Code Examples
- Basic route definition:
r1 := &eskip.Route{
Id: "hello",
Path: "/hello",
BackendType: eskip.NetworkBackend,
Backend: "https://example.org",
}
- Using filters to modify requests:
r2 := &eskip.Route{
Path: "/api",
Filters: []*eskip.Filter{
{Name: "setRequestHeader", Args: []interface{}{"X-Custom-Header", "foo"}},
{Name: "rateLimit", Args: []interface{}{10, "1m"}},
},
Backend: "https://api.example.com",
}
- Defining a route with predicates:
r3 := &eskip.Route{
Predicates: []*eskip.Predicate{
{Name: "Method", Args: []interface{}{"GET"}},
{Name: "Header", Args: []interface{}{"Accept", "application/json"}},
},
Path: "/data",
Backend: "https://data.example.com",
}
Getting Started
To get started with Skipper, follow these steps:
-
Install Skipper:
go get github.com/zalando/skipper/cmd/skipper
-
Create a simple routes file (e.g.,
routes.eskip
):* -> setResponseHeader("X-Powered-By", "Skipper") -> "https://example.org"
-
Run Skipper with the routes file:
skipper -routes-file routes.eskip
-
Test the proxy:
curl -v localhost:9090
This will start Skipper on port 9090, forwarding all requests to example.org and adding a custom header to the response.
Competitor Comparisons
The Cloud Native Application Proxy
Pros of Traefik
- More extensive feature set, including automatic HTTPS and Let's Encrypt integration
- Better documentation and community support
- Easier configuration with auto-discovery of services
Cons of Traefik
- Higher resource consumption, especially in large-scale deployments
- Steeper learning curve for advanced configurations
- Less flexibility in custom routing logic compared to Skipper
Code Comparison
Traefik configuration (YAML):
http:
routers:
my-router:
rule: "Host(`example.com`) && PathPrefix(`/api`)"
service: my-service
Skipper configuration (Eskip):
myroute: Host("example.com") && PathSubtree("/api")
-> setPath("/api")
-> "http://my-service";
Both Traefik and Skipper are popular reverse proxy and load balancing solutions. Traefik offers a more comprehensive feature set and easier configuration, making it suitable for various use cases. Skipper, developed by Zalando, provides more flexibility in custom routing logic and may be more efficient in large-scale deployments. The choice between the two depends on specific project requirements, scalability needs, and the desired level of customization.
Connect, secure, control, and observe services.
Pros of Istio
- More comprehensive service mesh solution with advanced traffic management, security, and observability features
- Robust ecosystem and wide industry adoption, leading to better community support and integrations
- Supports multiple platforms and environments, including Kubernetes and VMs
Cons of Istio
- Higher complexity and steeper learning curve compared to Skipper
- Requires more resources and can introduce performance overhead
- More challenging to set up and maintain in smaller or simpler environments
Code Comparison
Skipper route definition:
route1: Path("/foo") -> "https://example.org";
Istio VirtualService definition:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: example-vs
spec:
hosts:
- example.com
http:
- match:
- uri:
prefix: "/foo"
route:
- destination:
host: example.org
The code comparison shows that Skipper uses a more concise syntax for defining routes, while Istio requires a more verbose YAML configuration. This reflects the difference in complexity and feature set between the two projects, with Istio offering more advanced routing capabilities at the cost of increased configuration complexity.
Cloud-native high-performance edge/middle/service proxy
Pros of Envoy
- More extensive feature set, including advanced load balancing, observability, and security capabilities
- Larger community and ecosystem, with broader adoption in cloud-native environments
- Better performance and scalability for high-traffic scenarios
Cons of Envoy
- Steeper learning curve and more complex configuration
- Higher resource consumption, especially for smaller deployments
- Less focus on simplicity and ease of use compared to Skipper
Code Comparison
Skipper route definition:
route1: Path("/api/v1") -> "https://api.example.com";
Envoy route configuration:
routes:
- match:
prefix: "/api/v1"
route:
cluster: api_cluster
Summary
Envoy is a more feature-rich and widely adopted proxy, suitable for complex, high-performance scenarios in cloud-native environments. It offers advanced capabilities but comes with increased complexity and resource usage. Skipper, on the other hand, focuses on simplicity and ease of use, making it a good choice for smaller deployments or teams prioritizing quick setup and straightforward configuration. The choice between the two depends on specific project requirements, team expertise, and scalability needs.
🦍 The Cloud-Native API Gateway and AI Gateway.
Pros of Kong
- More extensive plugin ecosystem with 100+ plugins available
- Supports multiple databases (PostgreSQL, Cassandra) for configuration storage
- Offers enterprise features and commercial support options
Cons of Kong
- Heavier resource footprint, potentially higher operational costs
- More complex setup and configuration process
- Steeper learning curve for newcomers
Code Comparison
Kong (Lua):
local kong = kong
local request_uri = ngx.var.request_uri
if string.match(request_uri, "^/api/") then
kong.service.request.set_path("/v1" .. request_uri:sub(5))
end
Skipper (Go):
r.Handle("/api/*", eskip.NewProxy(
eskip.NewStaticBackend("https://api.example.com"),
eskip.ModPath("^/api", "/v1"),
))
Both examples show how to modify the request path for API routing, but Kong uses Lua within the NGINX configuration, while Skipper uses Go with its custom DSL.
Kong offers more out-of-the-box features and a larger ecosystem, making it suitable for complex, enterprise-grade deployments. Skipper, on the other hand, is lighter, more focused on Kubernetes integration, and easier to get started with for simpler use cases. The choice between them depends on specific project requirements, existing infrastructure, and team expertise.
The official NGINX Open Source repository.
Pros of nginx
- Widely adopted and battle-tested in production environments
- Excellent performance and low resource usage
- Extensive documentation and community support
Cons of nginx
- Less flexible routing capabilities compared to Skipper
- Configuration can be complex for advanced use cases
- Limited built-in support for modern microservices patterns
Code Comparison
nginx configuration:
http {
server {
listen 80;
location / {
proxy_pass http://backend;
}
}
}
Skipper route:
r1: * -> setPath("/api") -> "https://api.example.com";
Summary
nginx is a well-established web server and reverse proxy with excellent performance and widespread adoption. It excels in traditional web serving scenarios but may require more effort for complex routing in microservices architectures.
Skipper, on the other hand, is designed specifically for modern API gateway and microservices use cases. It offers more flexible routing capabilities and easier integration with Kubernetes environments. However, it may not have the same level of maturity and community support as nginx.
The choice between nginx and Skipper depends on the specific requirements of your project, with nginx being a solid choice for general-purpose web serving and Skipper offering advantages in microservices-oriented architectures.
HAProxy Load Balancer's development branch (mirror of git.haproxy.org)
Pros of HAProxy
- Mature and battle-tested: HAProxy has been around since 2001, offering robust performance and reliability
- Extensive feature set: Supports a wide range of load balancing algorithms, SSL termination, and advanced health checks
- High performance: Known for its ability to handle large numbers of concurrent connections efficiently
Cons of HAProxy
- Configuration complexity: Can be more challenging to configure compared to Skipper, especially for beginners
- Less focus on API gateway features: While it can be used as an API gateway, it's not its primary focus like Skipper
- Limited dynamic reconfiguration: Requires more effort to implement dynamic routing changes compared to Skipper
Code Comparison
HAProxy configuration example:
frontend http-in
bind *:80
default_backend servers
backend servers
balance roundrobin
server server1 127.0.0.1:8000 check
server server2 127.0.0.1:8001 check
Skipper route definition example:
r1: * -> setPath("/api/v1") -> "https://api.example.com";
r2: Path("/foo") -> setPath("/bar") -> "https://backend.example.com";
While HAProxy uses a more traditional configuration file format, Skipper employs a domain-specific language for defining routes, which can be more intuitive for API gateway use cases.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
Skipper
Skipper is an HTTP router and reverse proxy for service composition. It's designed to handle >300k HTTP route definitions with detailed lookup conditions, and flexible augmentation of the request flow with filters. It can be used out of the box or extended with custom lookup, filter logic and configuration sources.
Main features:
An overview of deployments and data-clients shows some use cases to run skipper.
Skipper
- identifies routes based on the requests' properties, such as path, method, host and headers
- allows modification of the requests and responses with filters that are independently configured for each route
- simultaneously streams incoming requests and backend responses
- optionally acts as a final endpoint (shunt), e.g. as a static file server or a mock backend for diagnostics
- updates routing rules without downtime, while supporting multiple types of data sources â including etcd, Kubernetes Ingress, static files, route string and custom configuration sources
- can serve as a Kubernetes Ingress controller without reloads. You can use it in combination with a controller that will route public traffic to your skipper fleet; see AWS example
- shipped with
- eskip: a descriptive configuration language designed for routing rules
- routesrv: proxy to omit kube-apiserver overload leveraging Etag header to reduce amount of CPU used in your skipper data plane
- webhook: Kubernetes validation webhook to make sure your manifests are deployed safely
Skipper provides a default executable command with a few built-in filters. However, its primary use case is to be extended with custom filters, predicates or data sources. Go here for additional documentation.
A few examples for extending Skipper:
- Example proxy with custom filter https://github.com/szuecs/skipper-example-proxy
- Image server https://github.com/zalando-stups/skrop
- Plugins repository https://github.com/skipper-plugins/, plugin docs
Getting Started
Prerequisites/Requirements
In order to build and run Skipper, only the latest version of Go needs to be installed. Skipper can use Innkeeper or Etcd as data sources for routes, or for the simplest cases, a local configuration file. See more details in the documentation: https://pkg.go.dev/github.com/zalando/skipper
Installation
From Binary
Download binary tgz from https://github.com/zalando/skipper/releases/latest
Example, assumes that you have $GOBIN set to a directory that exists and is in your $PATH:
% curl -LO https://github.com/zalando/skipper/releases/download/v0.14.8/skipper-v0.14.8-linux-amd64.tar.gz
% tar xzf skipper-v0.14.8-linux-amd64.tar.gz
% mv skipper-v0.14.8-linux-amd64/* $GOBIN/
% skipper -version
Skipper version v0.14.8 (commit: 95057948, runtime: go1.19.1)
From Source
% git clone https://github.com/zalando/skipper.git
% make
% ./bin/skipper -version
Skipper version v0.14.8 (commit: 95057948, runtime: go1.19.3)
Running
Create a file with a route:
echo 'hello: Path("/hello") -> "https://www.example.org"' > example.eskip
Optionally, verify the file's syntax:
eskip check example.eskip
If no errors are detected nothing is logged, else a descriptive error is logged.
Start Skipper and make an HTTP request:
skipper -routes-file example.eskip &
curl localhost:9090/hello
Docker
To run the latest Docker container:
docker run registry.opensource.zalan.do/teapot/skipper:latest
To run eskip
you first mount the .eskip
file, into the container, and run the command
docker run \
-v $(PWD)/doc-docker-intro.eskip:/doc-docker-intro.eskip \
registry.opensource.zalan.do/teapot/skipper:latest eskip print doc-docker-intro.eskip
To run skipper
you first mount the .eskip
file, into the container, expose the ports and run the command
docker run -it \
-v $(PWD)/doc-docker-intro.eskip:/doc-docker-intro.eskip \
-p 9090:9090 \
-p 9911:9911 \
registry.opensource.zalan.do/teapot/skipper:latest skipper -routes-file doc-docker-intro.eskip
Skipper will then be available on http://localhost:9090
Authentication Proxy
Skipper can be used as an authentication proxy, to check incoming requests with Basic auth or an OAuth2 provider or an OpenID Connect provider including audit logging. See the documentation at: https://pkg.go.dev/github.com/zalando/skipper/filters/auth.
Working with the code
Getting the code with the test dependencies (-t
switch):
git clone https://github.com/zalando/skipper.git
cd skipper
Build and test all packages:
make deps
make install
make lint
make shortcheck
On Mac the tests may fail because of low max open file limit. Please make sure you have correct limits setup by following these instructions.
Working from IntelliJ / GoLand
To run or debug skipper from IntelliJ IDEA or GoLand, you need to create this configuration:
Parameter | Value |
---|---|
Template | Go Build |
Run kind | Directory |
Directory | skipper source dir + /cmd/skipper |
Working directory | skipper source dir (usually the default) |
Kubernetes Ingress
Skipper can be used to run as an Kubernetes Ingress controller. Details with examples of Skipper's capabilities and an overview you will can be found in our ingress-controller deployment docs.
For AWS integration, we provide an ingress controller https://github.com/zalando-incubator/kube-ingress-aws-controller, that manage ALBs or NLBs in front of your skipper deployment. A production example for skipper and a production example for kube-ingress-aws-controller, can be found in our Kubernetes configuration https://github.com/zalando-incubator/kubernetes-on-aws.
Documentation
Skipper's Documentation and Godoc developer documentation, includes information about deployment use cases and detailed information on these topics:
- The Routing Mechanism
- Matching Requests
- Filters - Augmenting Requests and Responses
- Predicates - additional predicates to match a route
- Service Backends
- Route Definitions fetched by dataclients:
- Circuit Breakers
- Extending It with Custom Predicates, Filters, can be done by building your own proxy, Plugins or Lua Scripts
- Proxy Package
- Logging and Metrics
- Operations guide
- Authentication and Authorization
- Load Shedders
- Rate Limiters
- Opentracing tracers or extend create your own
1 Minute Skipper introduction
The following example shows a skipper routes file in eskip format, that has 3 named routes: baidu, google and yandex.
% cat doc-1min-intro.eskip
baidu:
Path("/baidu")
-> setRequestHeader("Host", "www.baidu.com")
-> setPath("/s")
-> setQuery("wd", "godoc skipper")
-> "http://www.baidu.com";
google:
*
-> setPath("/search")
-> setQuery("q", "godoc skipper")
-> "https://www.google.com";
yandex:
* && Cookie("yandex", "true")
-> setPath("/search/")
-> setQuery("text", "godoc skipper")
-> tee("http://127.0.0.1:12345/")
-> "https://yandex.ru";
Matching the route:
- baidu is using
Path()
matching to differentiate the HTTP requests to select the route. - google is the default matching with wildcard
*
- yandex is the default matching with wildcard
*
if you have a cookieyandex=true
Request Filters:
- If baidu is selected, skipper sets the Host header, changes the path and sets a query string to the http request to the backend "http://www.baidu.com".
- If google is selected, skipper changes the path and sets a query string to the http request to the backend "https://www.google.com".
- If yandex is selected, skipper changes the path and sets a query string to the http request to the backend "https://yandex.ru". The modified request will be copied to "http://127.0.0.1:12345/"
Run skipper with the routes file doc-1min-intro.eskip shown above
% skipper -routes-file doc-1min-intro.eskip
To test each route you can use curl:
% curl -v localhost:9090/baidu
% curl -v localhost:9090/
% curl -v --cookie "yandex=true" localhost:9090/
To see the shadow traffic request that is made by the tee()
filter you can use nc:
[terminal1]% nc -l 12345
[terminal2]% curl -v --cookie "yandex=true" localhost:9090/
3 Minutes Skipper in Kubernetes introduction
This introduction was moved to ingress controller documentation.
For More details, please check out our Kubernetes ingress controller docs, our ingress usage and how to handle common backend problems in Kubernetes.
Packaging support
See https://github.com/zalando/skipper/blob/master/packaging/readme.md
In case you want to implement and link your own modules into your
skipper, there is https://github.com/skipper-plugins organization to
enable you to do so. In order to explain you the build process with
custom Go modules there is
https://github.com/skipper-plugins/skipper-tracing-build, that was
used to build skipper's opentracing package.
We moved the opentracing plugin source into the tracing
package, so
there is no need to use plugins for this case.
Because Go plugins are not very well supported by Go itself we do not recommend to use plugins, but you can extend skipper and build your own proxy.
Community
User or developer questions can be asked in our public Google Group
We have a slack channel #skipper in gophers.slack.com. Get an invite. If for some reason this link doesn't work, you can find more information about the gophers communities here.
The preferred communication channel is the slack channel, because the google group is a manual process to add members. Feel also free to create an issue, if you dislike chat and post your questions there.
Proposals
We do our proposals open in Skipper's Google drive. If you want to make a proposal feel free to create an issue and if it is a bigger change we will invite you to a document, such that we can work together.
Users
Zalando used this project as shop frontend http router with 350000 routes. We use it as Kubernetes ingress controller in more than 100 production clusters. With every day traffic between 500k and 7M RPS serving 15000 ingress and 3750 RouteGroups at less than ¢5/1M requests. We also run several custom skipper instances that use skipper as library.
Sergio Ballesteros from spotahome said 2018:
We also ran tests with several ingress controllers and skipper gave us the more reliable results. Currently we are running skipper since almost 2 years with like 20K Ingress rules. The fact that skipper is written in go let us understand the code, add features and fix bugs since all of our infra stack is golang.
In the media
Blog posts:
- opensource.com - Try this Kubernetes HTTP router and reverse proxy
- opensource.com - An open source HTTP router to increase your network visibility
- Building our own open source http routing solution: Giving some context about why Skipper was created in the first place.
- Kubernetes in production @ ShopGun
- Hacker News Skipper â An HTTP router and reverse proxy for service composition
Conference/Meetups talks
Version promise
Skipper will update the minor version in case we have either:
- a significant change
- a Go version requirement change (
go
directive in go.mod change) - a dependency change that adds or removes a
replace
directive in go.mod file (requires library users to add or remove the same directive in their go.mod file) - a change that require attention to users, for example Kubernetes RBAC changes required to deploy https://github.com/zalando/skipper/releases/tag/v0.18.0
- a feature removal like Kubernetes ingress v1beta1 https://github.com/zalando/skipper/releases/tag/v0.15.0
- an API change of a function that is marked experimental example
We expect that skipper library users will use
skipper.Run(skipper.Options{})
as main interface that we do not want
to break. Besides the Kubernetes v1beta1 removal there was never a
change that removed an option. We also do not want to break generic
useful packages like net
. Sometimes we mark library functions, that
we expect to be useful as experimental, because we want to try and
learn over time if this is a good API decision or if this limits us.
This promise we hold considering the main, filter, predicate, dataclient, eskip interfaces and generic packages. For other packages, we have more weak promise with backwards compatibility as these are more internal packages. We try to omit breaking changes also in internal packages. If this would mean too much work or impossible to build new functionality as we would like, we will do a breaking change considering strictly semantic versioning rules.
How to update
Every update that changes the minor version (the m
in v0.m.p
),
should be done by +1
only. So v0.N.x
to v0.N+1.y
and you should
read v0.N+1.0
release page to see what can break and what you have
to do in order to have no issues while updating.
Top Related Projects
The Cloud Native Application Proxy
Connect, secure, control, and observe services.
Cloud-native high-performance edge/middle/service proxy
🦍 The Cloud-Native API Gateway and AI Gateway.
The official NGINX Open Source repository.
HAProxy Load Balancer's development branch (mirror of git.haproxy.org)
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot