Giter VIP home page Giter VIP logo

namespace-provisioner's Introduction

⚠️ This project is no longer maintained and is archived.

Namespace Provisioner

CI Go Report Card MIT License GitHub Release

The Namespace Provisioner is a Kubernetes Operator that facilitates the management of multiple namespaces on kubernetes clusters. You can simply annotate a Kubernetes namespace and non-application specific resources like ImagePullSecrets, NetworkPolicies, Roles or RoleBindings are automatically deployed to prepare the namespace for application deployment and testing.

Why to use the Namespace Provisioner?

If your development team uses patterns like one namespace per feature branch (or pull request) you have to manage many volatile namespaces. To prepare these namespaces for deployment of your microservices and applications, it’s necessary to install resources like ImagePullSecrets, NetworkPolicies, Roles,RoleBindings or a Tiller deployment.

This can be included in the CI/CD pipeline of your application, but if you have multiple pipelines (for your multiple micro services) this can lead to duplication of pipeline code and/or deployment files (Kubernetes or Helm).

Another approach is to use a separate prepare pipeline, which installs the resources and is run before every microservice pipeline. This can lead to complicated pipeline chains, which are hard to maintain and slow down your CI/CD environment.

With the Namespace Provisioner, the preparation of namespaces can be achieved very easily:

  • Store the kubernetes configurations (i.e. the yaml files) of the resources in a ConfigMap or Secret and give them a meaningful name like image-pull-secrets, rbac-rules or tiller-deployment.
    • Multiple configurations can be stored in one ConfigMap or Secret by using the standard document separator ---
  • Install the Namespace Provisioner operator (see Installation).
    • The namespace where your kubernetes configurations are stored can be configured by environment variable CONFIG_NAMESPACE. By default the default namespace is used.
  • For every new namespace add an annotation to inform the provisioner:
    • If you stored your kubernetes configurations in an ConfigMap, use the annotation key namespace-provisioner.daimler-tss.com/config.
    • If you stored your kubernetes configurations in an Secret, use the annotation key namespace-provisioner.daimler-tss.com/secret.
    • You can set both annotations if needed.
    • The value for the annotation is a comma separated list of names of your ConfigMaps or Secrets, e.g. namespace-provisioner.daimler-tss.com/config=rbac-rules,tiller-deployment

Deployment of Namespace Provisioner

Demo

Create a new namespace and annotate it to deploy NetworkPolicies.

Demo

Installation

Building from source

In order to build the namespace-provisioner Docker image from source you need the following tools:

TL;DR

# Build the binary and Docker image
task docker:build

# List images
docker images docker.pkg.github.com/daimler/namespace-provisioner/namespace-provisioner

Usage

The operator needs permissions to deploy new resources in newly created namespaces. Therefore you need a kubernetes config file which includes a user with the correct permissions and the credentials. The easiest way is to add your kubernetes config file, which you also use with your kubectl command.

TL;DR

# Deploy secrets
task deploy-secrets

# Deploy namespace-provisioner to minikube
task deploy-local

Step by step

# Optional: set the context for the cluster you want to deploy namespace-provisioner to
kubectl config use-context minikube

# Get the kubernetes config file to access your tenant and replace server url
kubectl config view --raw --minify=true --flatten=true | \
  sed "s/server:.*/server: https:\/\/kubernetes.default.svc/g" > config

# Create secret deployment file for kube-config and deploy the secret
kubectl create secret generic kube-config --from-file=config --dry-run -oyaml | kubectl apply -f -

# Create deployment file
cat << EOF > namespace-provisioner.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: namespace-provisioner-deployment
  labels:
    app: namespace-provisioner
spec:
  replicas: 1
  selector:
    matchLabels:
      app: namespace-provisioner
  template:
    metadata:
      labels:
        app: namespace-provisioner
    spec:
      containers:
      - name: namespace-provisioner
        image: docker.pkg.github.com/daimler/namespace-provisioner/namespace-provisioner:latest
        imagePullPolicy: IfNotPresent
        env:
        - name: LOG_LEVEL
          value: DEBUG
        - name: CONFIG_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        - name: KUBECONFIG
          value: /.kube/config
        volumeMounts:
        - name: kube-config
          mountPath: /.kube
      volumes:
      - name: kube-config
        secret:
          secretName: kube-config
          items:
          - key: config
            path: config
            mode: 511
EOF

# Deploy the namespace-provisioner
kubectl apply -f namespace-provisioner.yaml

Example: Prepare Prometheus deployment

For every annotated namespace, all traffic from app prometheus in namespace kube-system to any pod should be allowed. Therefore the namespace provisioner should create a corresponding NetworkPolicy.

Please note that the example might require adaptions depending on your Kubernetes version.

Prepare the corresponding namespace-provisioner config in default namespace:

cat << EOF > namespace-provisioning-networkpolicy.yaml
# Default deny all ingress traffic
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny
spec:
  podSelector: {}
  policyTypes:
  - Ingress
---
# Allow all traffic from app prometheus in namespace kube-system to any pod
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: kube-system.app.prometheus-allow-all
spec:
  podSelector: {}
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          name: kube-system
      podSelector:
        matchLabels:
          app: prometheus
EOF

# Deploy namespace-provisioning-networkpolicy ConfigMap
kubectl --namespace=default create configmap namespace-provisioning-networkpolicy --from-file=namespace-provisioning-networkpolicy.yaml

Create a new namespace:

# Create new namespace
kubectl create ns my-namespace

# Add annotation to namespace --> namespace-provisioner deploys all ConfigMaps
# Multiple ConfigMaps are separated by comma; e.g namespace-provisioner.daimler-tss.com/config=c1,c2,c3
kubectl annotate ns my-namespace namespace-provisioner.daimler-tss.com/config=namespace-provisioning-networkpolicy

Check if network policies are deployed:

$ kubectl --namespace=my-namespace get netpol
NAME                                   POD-SELECTOR   AGE
default-deny                           <none>         13s
kube-system.app.prometheus-allow-all   <none>         13s

Development

Multi-stage build

To build the Docker image from source you need Task (≥ 2.8.0) and Docker (≥ 18.09).

# Build Go binary and Docker image
task docker:build

# Run tests
task docker:test

Local build

To build and test the operator on your local OS you need Task (≥ 2.8.0) and Go (≥ 1.13).

# Build Go binary
task local:build

# Run tests
task local:test

# Clean up workspace
task local:clean

Running in IDE

To build and run the operator in your IDE, run the Go file main.go.

If you don’t want to use the default kube config file, set the env variable KUBECONFIG:

export KUBECONFIG=/home/<USER>/.kube/config

Known issues

  • Currently the contents of the config map is deployed only once, when the annotation on the namespace is created. Therefore, if the content of the config map changes, the changes are not deployed anymore.
    • Could be fixed by storing the mapping ConfigMap-Namespaces and watching the ConfigMap. If a ConfigMap changes, update contents to all namespaces.
  • Currently the namespace-provisioner has no prometheus monitoring included.

Contributing

We welcome any contributions. If you want to contribute to this project, please read the contributing guide.

Code of Conduct

Please read our Code of Conduct as it is our base for interaction.

License

This project is licensed under the MIT License.

Provider Information

Please visit https://www.daimler-tss.com/en/imprint/ for information on the provider.

Notice: Before you use the program in productive use, please take all necessary precautions, e.g. testing and verifying the program with regard to your specific use. The program was tested solely for our own use cases, which might differ from yours.

namespace-provisioner's People

Contributors

ffurrer2 avatar ogruene avatar

Stargazers

Benjamin Hahn avatar Yagnesh Mistry avatar  avatar Francesco Della Coletta avatar Fabien Lesire avatar Denis Trofimov avatar Pavel Tishkov avatar Sergej Domme avatar John Blesener avatar Zadkiel AHARONIAN avatar Jason Roberts avatar ArthurMa avatar Vlad Voloshyn avatar Eugene Starchenko avatar SUBHAKAR avatar Njegos Railic avatar Bruno Lopes avatar  avatar Tobias Giese avatar Minoru Mizutani avatar Caetano D'Araujo avatar Mithun Singh avatar  avatar Benjamin Auwärter avatar Alan Grosskurth avatar Sascha avatar Sergei Monakhov avatar  avatar Ionut Zaharia avatar  avatar Sascha Winkelhofer avatar  avatar Jonas von Malottki avatar Oliver Kopp avatar Hugo Fonseca avatar Marc Samendinger avatar William Zhang avatar Mario Constanti avatar Toan Tran avatar Bogdan Dinu avatar Rimantas (Rimas) Mocevicius avatar  avatar  avatar Giterrific avatar Joerg Schmidt avatar Bjoern Stuetz avatar Chris P. avatar Peter Mueller avatar Philipp Bormann avatar  avatar

Watchers

 avatar James Cloos avatar Benjamin Auwärter avatar Segfault16 avatar Kerstin Maier avatar  avatar  avatar Allen Hammond avatar  avatar Benjamin Hahn avatar Peter Mueller avatar Fabian F avatar

namespace-provisioner's Issues

RFC: Use a ServiceAccount rather than user-supplied .kube/config

Hi,

I was following the README file to set up the namespace provisioner in minikube. The step that required me to supply my own kube config didn't work quite as expected, since minkube hardcodes path to certificates and private key to host paths, rather than supplying them as base64-encoded '-data'. Additionally, I wasn't sure about adding user account data to a service made any sense. So, I found out there's something called ServiceAccount, which was made exactly for these purposes.

I modified the installation as follows:

  • Create ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
  name: namespace-provisioner
  • Create ClusterRole (way too permissive one)
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: namespace-provisioner
rules:
  - apiGroups: ["", "batch", "extensions", "apps", "rbac.authorization.k8s.io", "networking.k8s.io"]
    resources: ["*"]
    verbs: ["*"]
  • Create ClusterRoleBinding, ServiceAccount -> ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: namespace-provisioner
  namespace: default
subjects:
- kind: ServiceAccount
  name: namespace-provisioner
  namespace: default
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: namespace-provisioner
  • Modified the deployment as follows (added serviceAccountName)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: namespace-provisioner-deployment
  labels:
    app: namespace-provisioner
spec:
  replicas: 1
  selector:
    matchLabels:
      app: namespace-provisioner
  template:
    metadata:
      labels:
        app: namespace-provisioner
    spec:
      serviceAccountName: namespace-provisioner
      containers:
      - name: namespace-provisioner
...
  • Used the following .kube/config, and put it into kube-config ConfigMap
apiVersion: v1
clusters:
- cluster:
    certificate-authority: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
    server: https://kubernetes.default.svc
  name: default
contexts:
- context:
    cluster: default
    user: default
  name: default
current-context: default
kind: Config
preferences: {}
users:
- name: default
  user:
    tokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token

There are two things here that could be improved. First one is obviously cluster role, which is way too permissive, and should be restricted to what the namespace-provisioner can/should manage.

Second one is obviously providing hardcoded .kube/config from outside, when it can be placed inside docker image, or not used at all, and use the kubernetes API with service accounts, as intended.

Deployment in k8s 1.16 fails

The provided task deploy-local fails when trying to deploy the namespace provisioner into minikube with running k8s version 1.16, because the used apiVersion extensions/v1beta1 for Deployment is not served by default in k8s 1.16.

Docker image size looks quite large

When looking at the Docker image that is created using task docker:build it shows a size of approx. 80 MB although the Alpine base image's size is approx. 5 MB and the namespace-provisioner executable's size is approx. 37 MB.
When taking a detailed look at the layers of the image it can be noticed that there are 2 layers with exactly the same size and approx. the size of the namespace-provisioner's executable. Maybe there's something wrong with the Docker image creation.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.