allow caddy to be configured by config map

This commit is contained in:
dev 2019-06-19 14:42:46 -04:00 committed by Danny Navarro
parent a17f132e7d
commit abe4a47df6
6 changed files with 155 additions and 28 deletions

View File

@ -9,7 +9,9 @@ import (
) )
// ConvertToCaddyConfig returns a new caddy routelist based off of ingresses managed by this controller. // ConvertToCaddyConfig returns a new caddy routelist based off of ingresses managed by this controller.
func ConvertToCaddyConfig(ings []*v1beta1.Ingress) (caddyhttp.RouteList, []string, error) { // This is not used when this ingress controller is configured with a config map, so that we don't
// override user defined routes.
func ConvertToCaddyConfig(ings []*v1beta1.Ingress) (caddyhttp.RouteList, error) {
// ~~~~ // ~~~~
// TODO :- // TODO :-
// when setting the upstream url we should should bypass kube-dns and get the ip address of // when setting the upstream url we should should bypass kube-dns and get the ip address of
@ -17,15 +19,10 @@ func ConvertToCaddyConfig(ings []*v1beta1.Ingress) (caddyhttp.RouteList, []strin
// this is good for session affinity and increases performance. // this is good for session affinity and increases performance.
// ~~~~ // ~~~~
// record hosts for tls policies
var hosts []string
// create a server route for each ingress route // create a server route for each ingress route
var routes caddyhttp.RouteList var routes caddyhttp.RouteList
for _, ing := range ings { for _, ing := range ings {
for _, rule := range ing.Spec.Rules { for _, rule := range ing.Spec.Rules {
hosts = append(hosts, rule.Host)
for _, path := range rule.HTTP.Paths { for _, path := range rule.HTTP.Paths {
clusterHostName := fmt.Sprintf("%v.%v.svc.cluster.local", path.Backend.ServiceName, ing.Namespace) clusterHostName := fmt.Sprintf("%v.%v.svc.cluster.local", path.Backend.ServiceName, ing.Namespace)
r := baseRoute(clusterHostName) r := baseRoute(clusterHostName)
@ -46,7 +43,7 @@ func ConvertToCaddyConfig(ings []*v1beta1.Ingress) (caddyhttp.RouteList, []strin
} }
} }
return routes, hosts, nil return routes, nil
} }
func baseRoute(upstream string) caddyhttp.ServerRoute { func baseRoute(upstream string) caddyhttp.ServerRoute {

View File

@ -148,8 +148,8 @@ func (r ResourceDeletedAction) handle(c *CaddyController) error {
func updateConfig(c *CaddyController) error { func updateConfig(c *CaddyController) error {
// update internal caddy config with new ingress info // update internal caddy config with new ingress info
// serverRoutes, hosts, err := caddy.ConvertToCaddyConfig(c.resourceStore.Ingresses) if !c.usingConfigMap {
serverRoutes, _, err := caddy.ConvertToCaddyConfig(c.resourceStore.Ingresses) serverRoutes, err := caddy.ConvertToCaddyConfig(c.resourceStore.Ingresses)
if err != nil { if err != nil {
return errors.Wrap(err, "converting ingress resources to caddy config") return errors.Wrap(err, "converting ingress resources to caddy config")
} }
@ -164,6 +164,7 @@ func updateConfig(c *CaddyController) error {
if err != nil { if err != nil {
return errors.Wrap(err, "caddy config reload") return errors.Wrap(err, "caddy config reload")
} }
}
return nil return nil
} }

View File

@ -5,6 +5,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"log" "log"
"os" "os"
"time" "time"
@ -71,16 +72,25 @@ func NewCaddyController(kubeClient *kubernetes.Clientset, restClient rest.Interf
controller.podInfo = podInfo controller.podInfo = podInfo
// load caddy config from file if mounted with config map // load caddy config from file if mounted with config map
var caddyCfgMap caddy.Config
cfgPath := "/etc/caddy/config.json" cfgPath := "/etc/caddy/config.json"
if _, err := os.Stat(cfgPath); !os.IsNotExist(err) { if _, err := os.Stat(cfgPath); !os.IsNotExist(err) {
controller.usingConfigMap = true
file, err := os.Open(cfgPath) file, err := os.Open(cfgPath)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
defer file.Close() defer file.Close()
controller.usingConfigMap = true b, err := ioutil.ReadAll(file)
controller.syncQueue.Add(LoadConfigAction{config: file}) if err != nil {
log.Fatal(err)
}
// load config file into caddy
controller.syncQueue.Add(LoadConfigAction{config: bytes.NewReader(b)})
json.Unmarshal(b, &caddyCfgMap)
} }
// setup the ingress controller and start watching resources // setup the ingress controller and start watching resources
@ -94,7 +104,7 @@ func NewCaddyController(kubeClient *kubernetes.Clientset, restClient rest.Interf
controller.informer = informer controller.informer = informer
// setup store to keep track of resources // setup store to keep track of resources
controller.resourceStore = store.NewStore(controller.kubeClient, podInfo.Namespace, cfg) controller.resourceStore = store.NewStore(controller.kubeClient, podInfo.Namespace, cfg, &caddyCfgMap)
// attempt to do initial sync of status addresses with ingresses // attempt to do initial sync of status addresses with ingresses
controller.dispatchSync() controller.dispatchSync()

View File

@ -17,7 +17,7 @@ type Store struct {
// NewStore returns a new store that keeps track of ingresses and secrets. It will attempt to get // NewStore returns a new store that keeps track of ingresses and secrets. It will attempt to get
// all current ingresses before returning. // all current ingresses before returning.
func NewStore(kubeClient *kubernetes.Clientset, namespace string, cfg caddy.ControllerConfig) *Store { func NewStore(kubeClient *kubernetes.Clientset, namespace string, cfg caddy.ControllerConfig, cfgMapConfig *caddy.Config) *Store {
ingresses, err := kubeClient.ExtensionsV1beta1().Ingresses("").List(v1.ListOptions{}) ingresses, err := kubeClient.ExtensionsV1beta1().Ingresses("").List(v1.ListOptions{})
if err != nil { if err != nil {
logrus.Errorf("could not get existing ingresses in cluster") logrus.Errorf("could not get existing ingresses in cluster")
@ -26,7 +26,20 @@ func NewStore(kubeClient *kubernetes.Clientset, namespace string, cfg caddy.Cont
s := &Store{ s := &Store{
Ingresses: []*v1beta1.Ingress{}, Ingresses: []*v1beta1.Ingress{},
CaddyConfig: caddy.NewConfig(namespace, cfg), }
if cfgMapConfig == nil {
s.CaddyConfig = caddy.NewConfig(namespace, cfg)
} else {
// set cert-magic storage provider
cfgMapConfig.Storage = caddy.Storage{
System: "secret_store",
StorageValues: caddy.StorageValues{
Namespace: namespace,
},
}
s.CaddyConfig = cfgMapConfig
} }
for _, i := range ingresses.Items { for _, i := range ingresses.Items {

View File

@ -0,0 +1,96 @@
# this is an example config map for the caddy ingress controller
apiVersion: v1
kind: ConfigMap
metadata:
name: caddy-config
namespace: caddy-system
data:
config.json: '
{
"storage": {
"system": "secret_store",
"namespace": "caddy-system"
},
"apps": {
"http": {
"servers": {
"ingress_server": {
"listen": [
":80",
":443"
],
"routes": [
{
"match": [
{
"host": [
"danny2.kubed.co"
],
"path": [
"/hello2"
]
}
],
"apply": [
{
"middleware": "log",
"filename": "/etc/caddy/access.log"
}
],
"respond": {
"responder": "reverse_proxy",
"load_balance_type": "random",
"upstreams": [
{
"host": "http://example2.default.svc.cluster.local"
}
]
}
},
{
"match": [
{
"host": [
"danny2.kubed.co"
],
"path": [
""
]
}
],
"apply": [
{
"middleware": "log",
"filename": "/etc/caddy/access.log"
}
],
"respond": {
"responder": "reverse_proxy",
"load_balance_type": "random",
"upstreams": [
{
"host": "http://example.default.svc.cluster.local"
}
]
}
}
]
}
}
},
"tls": {
"automation": {
"policies": [
{
"management": {
"module": "acme",
"email": "test@test.com"
}
}
]
},
"session_tickets": {}
}
}
}
'

View File

@ -1,3 +1,7 @@
# uncomment the config map below
# if configuring caddy with a config map
# ensure that you update ./configmap.yaml
apiVersion: extensions/v1beta1 apiVersion: extensions/v1beta1
kind: Deployment kind: Deployment
metadata: metadata:
@ -31,13 +35,19 @@ spec:
volumes: volumes:
- name: tmp - name: tmp
emptyDir: {} emptyDir: {}
# - name: config-volume
# configMap:
# name: caddy-config
containers: containers:
- name: caddy-ingress-controller - name: caddy-ingress-controller
image: "gcr.io/danny-239313/ingresscontroller:v0.1.2" image: gcr.io/danny-239313/ingresscontroller
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
volumeMounts: volumeMounts:
- name: tmp - name: tmp
mountPath: /tmp mountPath: /tmp
# - name: config-volume
# mountPath: /etc/caddy/config.json
# subPath: config.json
securityContext: securityContext:
allowPrivilegeEscalation: true allowPrivilegeEscalation: true
capabilities: capabilities:
@ -64,4 +74,4 @@ spec:
fieldPath: metadata.namespace fieldPath: metadata.namespace
args: args:
- -tls - -tls
- -email=navdgo@gmail.com - -email=test@test.com