Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 50 additions & 29 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
#-------------------------------------------------------------------------------------------------------------

FROM node:13
FROM node:15

# Avoid warnings by switching to noninteractive
ENV DEBIAN_FRONTEND=noninteractive
Expand All @@ -17,39 +17,60 @@ ARG USER_UID=1000
ARG USER_GID=$USER_UID

# Configure apt and install packages
RUN apt-get update \
&& apt-get -y install --no-install-recommends apt-utils dialog 2>&1 \
RUN apt-get update && apt-get install -y --no-install-recommends \
apt-utils \
bash-completion \
ca-certificates \
curl \
dialog \
git \
iproute2 \
jq \
procps \
less \
vim \
#
# Verify git and needed tools are installed
&& apt-get -y install git iproute2 procps \
# Install bash completion
&& echo ". /etc/bash_completion" >> ~/.bashrc \
&& mkdir -p ~/completions \
#
# Remove outdated yarn from /opt and install via package
# so it can be easily updated via apt-get upgrade yarn
&& rm -rf /opt/yarn-* \
&& rm -f /usr/local/bin/yarn \
&& rm -f /usr/local/bin/yarnpkg \
&& apt-get install -y curl apt-transport-https lsb-release \
&& curl -sS https://dl.yarnpkg.com/$(lsb_release -is | tr '[:upper:]' '[:lower:]')/pubkey.gpg | apt-key add - 2>/dev/null \
&& echo "deb https://dl.yarnpkg.com/$(lsb_release -is | tr '[:upper:]' '[:lower:]')/ stable main" | tee /etc/apt/sources.list.d/yarn.list \
&& apt-get update \
&& apt-get -y install --no-install-recommends yarn \
#
# Install eslint globally
&& npm install -g eslint \
# Install node packages globally
&& npm install -g eslint pino-pretty \
#
# [Optional] Update a non-root user to UID/GID if needed.
&& if [ "$USER_GID" != "1000" ] || [ "$USER_UID" != "1000" ]; then \
groupmod --gid $USER_GID $USERNAME \
&& usermod --uid $USER_UID --gid $USER_GID $USERNAME \
&& chown -R $USER_UID:$USER_GID /home/$USERNAME; \
fi \
# [Optional] Add add sudo support for non-root user
# Add add sudo support for non-root user
&& apt-get install -y sudo \
&& echo node ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \
&& chmod 0440 /etc/sudoers.d/$USERNAME \
#
# Clean up
&& apt-get autoremove -y \
&& chmod 0440 /etc/sudoers.d/$USERNAME

# Install Docker CE CLI
RUN apt-get install -y apt-transport-https ca-certificates curl gnupg-agent software-properties-common lsb-release \
&& curl -fsSL https://download.docker.com/linux/$(lsb_release -is | tr '[:upper:]' '[:lower:]')/gpg | (OUT=$(apt-key add - 2>&1) || echo $OUT) \
&& add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/$(lsb_release -is | tr '[:upper:]' '[:lower:]') $(lsb_release -cs) stable" \
&& apt-get update \
&& apt-get install -y docker-ce-cli \
&& curl -L https://raw.githubusercontent.com/docker/docker-ce/master/components/cli/contrib/completion/bash/docker -o ~/completions/docker.bash \
&& echo "source ~/completions/docker.bash" >> ~/.bashrc

# Install Helm
RUN mkdir /tmp/helm \
&& curl -L https://get.helm.sh/helm-$(curl -s https://api.github.com/repos/helm/helm/releases/latest | jq -r .tag_name)-linux-amd64.tar.gz | tar xz -C /tmp/helm --strip-components 1 \
&& mv /tmp/helm/helm /usr/local/bin/ \
&& chmod +x /usr/local/bin/helm \
&& rm -fr /tmp/helm \
&& helm completion bash > ~/completions/helm.bash \
&& echo "source ~/completions/helm.bash" >> ~/.bashrc

# Install kubectl
RUN curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" \
&& chmod +x ./kubectl \
&& mv ./kubectl /usr/local/bin/kubectl \
&& kubectl completion bash > ~/completions/kubectl.bash \
&& echo "source ~/completions/kubectl.bash" >> ~/.bashrc \
&& echo "alias k=kubectl" >> ~/.bashrc \
&& echo "complete -o default -F __start_kubectl k" >> ~/.bashrc

# Clean up
RUN apt-get autoremove -y \
&& apt-get clean -y \
&& rm -rf /var/lib/apt/lists/*

Expand Down
6 changes: 5 additions & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
// For format details, see https://aka.ms/vscode-remote/devcontainer.json or the definition README at
// https://github.com/microsoft/vscode-dev-containers/tree/master/containers/javascript-node-12
{
"name": "Node.js 13",
"name": "Development environment - hello-kubernetes",
"dockerFile": "Dockerfile",
"mounts": [
"source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind",
"source=${env:HOME}${env:USERPROFILE}/.kube,target=/root/.kube,type=bind"
],

// Use 'settings' to set *default* container specific settings.json values on container create.
// You can edit these settings after create using File > Preferences > Settings > Remote.
Expand Down
4 changes: 0 additions & 4 deletions .dockerignore

This file was deleted.

5 changes: 3 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
# Dependency directories
node_modules/
# Dependency directories and files
node_modules/
package-lock.json
22 changes: 22 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
REGISTRY ?= docker.io
REPOSITORY ?= paulbouwer
IMAGE_VERSION ?= $(shell cat src/app/package.json | jq -r .version)
IMAGE_MAJOR_VERSION = $(shell echo "$(IMAGE_VERSION)" | cut -d '.' -f1 )
IMAGE_MINOR_VERSION = $(shell echo "$(IMAGE_VERSION)" | cut -d '.' -f2 )
IMAGE = $(REGISTRY)/$(REPOSITORY)/hello-kubernetes

.PHONY: build-image-linux
build-image-linux:
docker build --no-cache \
--build-arg IMAGE_VERSION="$(IMAGE_VERSION)" \
--build-arg IMAGE_CREATE_DATE="`date -u +"%Y-%m-%dT%H:%M:%SZ"`" \
--build-arg IMAGE_SOURCE_REVISION="`git rev-parse HEAD`" \
-f src/app/Dockerfile -t "$(IMAGE):$(IMAGE_VERSION)" src/app;

.PHONY: push-image
push-image:
docker tag $(IMAGE):$(IMAGE_VERSION) $(IMAGE):$(IMAGE_MAJOR_VERSION); \
docker tag $(IMAGE):$(IMAGE_VERSION) $(IMAGE):$(IMAGE_MAJOR_VERSION).$(IMAGE_MINOR_VERSION); \
docker push $(IMAGE):$(IMAGE_VERSION); \
docker push $(IMAGE):$(IMAGE_MAJOR_VERSION); \
docker push $(IMAGE):$(IMAGE_MAJOR_VERSION).$(IMAGE_MINOR_VERSION)
203 changes: 39 additions & 164 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,195 +2,70 @@

[![Docker Image Version (latest by date)](https://img.shields.io/docker/v/paulbouwer/hello-kubernetes)](https://hub.docker.com/repository/docker/paulbouwer/hello-kubernetes) [![Docker Image Size (latest by date)](https://img.shields.io/docker/image-size/paulbouwer/hello-kubernetes)](https://hub.docker.com/repository/docker/paulbouwer/hello-kubernetes) [![Docker Pulls](https://img.shields.io/docker/pulls/paulbouwer/hello-kubernetes)](https://hub.docker.com/repository/docker/paulbouwer/hello-kubernetes)

This container image can be deployed on a Kubernetes cluster. When accessed via a web browser on port `8080`, it will display:
This container image can be deployed on a Kubernetes cluster. It runs a web app, that displays the following:

- a default **Hello world!** message
- the pod name
- node os information
- namespace, pod, and node details
- container image details

![Hello world! from the hello-kubernetes image](hello-kubernetes.png)

The default "Hello world!" message displayed can be overridden using the `MESSAGE` environment variable. The default port of 8080 can be overriden using the `PORT` environment variable.

## Deploy

### Standard Configuration

Deploy to your Kubernetes cluster using the hello-kubernetes.yaml, which contains definitions for the service and deployment objects:

```yaml
# hello-kubernetes.yaml
apiVersion: v1
kind: Service
metadata:
name: hello-kubernetes
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: 8080
selector:
app: hello-kubernetes
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-kubernetes
spec:
replicas: 3
selector:
matchLabels:
app: hello-kubernetes
template:
metadata:
labels:
app: hello-kubernetes
spec:
containers:
- name: hello-kubernetes
image: paulbouwer/hello-kubernetes:1.9
ports:
- containerPort: 8080
```
## Quick start

You can deploy `hello-kubernetes` to your Kubernetes cluster using [Helm 3](https://helm.sh/docs/intro/install/). The Helm chart installation and configuration options can be found in the [Deploy using Helm](docs/deploy-using-helm.md) guide.

When running through the following examples, ensure that you are in the chart directory in the repo, since you are referencing a local helm chart.

```bash
$ kubectl apply -f yaml/hello-kubernetes.yaml
cd deploy/helm
```

This will display a **Hello world!** message when you hit the service endpoint in a browser. You can get the service endpoint ip address by executing the following command and grabbing the returned external ip address value:
### Example 1: Default

Deploy the `hello-kubernetes` app into the `hello-kubernetes` namespace with the default "Hello world!" message. The app is exposed via a public Load Balancer on port 80 by default - note that a LoadBalancer service typically only works in cloud provider based Kubernetes offerings.

```bash
$ kubectl get service hello-kubernetes
```
helm install --create-namespace --namespace hello-kubernetes hello-world ./hello-kubernetes

### Customise Message

You can customise the message displayed by the `hello-kubernetes` container. Deploy using the hello-kubernetes.custom-message.yaml, which contains definitions for the service and deployment objects.

In the definition for the deployment, add an `env` variable with the name of `MESSAGE`. The value you provide will be displayed as the custom message.

```yaml
# hello-kubernetes.custom-message.yaml
apiVersion: v1
kind: Service
metadata:
name: hello-kubernetes-custom
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: 8080
selector:
app: hello-kubernetes-custom
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-kubernetes-custom
spec:
replicas: 3
selector:
matchLabels:
app: hello-kubernetes-custom
template:
metadata:
labels:
app: hello-kubernetes-custom
spec:
containers:
- name: hello-kubernetes
image: paulbouwer/hello-kubernetes:1.9
ports:
- containerPort: 8080
env:
- name: MESSAGE
value: I just deployed this on Kubernetes!
# get the LoadBalancer ip address.
kubectl get svc hello-kubernetes-hello-world -n hello-kubernetes -o 'jsonpath={ .status.loadBalancer.ingress[0].ip }'
```

### Example 2: Custom message

Deploy the `hello-kubernetes` app into the `hello-kubernetes` namespace with an "I just deployed this on Kubernetes!" message. The app is exposed via a public Load Balancer on port 80 by default - note that a LoadBalancer service typically only works in cloud provider based Kubernetes offerings.

```bash
$ kubectl apply -f yaml/hello-kubernetes.custom-message.yaml
```
helm install --create-namespace --namespace hello-kubernetes custom-message ./hello-kubernetes \
--set message="I just deployed this on Kubernetes!"

### Specify Custom Port

By default, the `hello-kubernetes` app listens on port `8080`. If you have a requirement for the app to listen on another port, you can specify the port via an env variable with the name of PORT. Remember to also update the `containers.ports.containerPort` value to match.

Here is an example:

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-kubernetes-custom
spec:
replicas: 3
selector:
matchLabels:
app: hello-kubernetes-custom
template:
metadata:
labels:
app: hello-kubernetes-custom
spec:
containers:
- name: hello-kubernetes
image: paulbouwer/hello-kubernetes:1.9
ports:
- containerPort: 80
env:
- name: PORT
value: "80"
# get the LoadBalancer ip address.
kubectl get svc hello-kubernetes-custom-message -n hello-kubernetes -o 'jsonpath={ .status.loadBalancer.ingress[0].ip }'
```

## Cutomize URL context path

If you have an ingress that routes to a custom context path then you can customize the URL context path. The css files and the images will be loaded properly in that case.

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-kubernetes-custom
spec:
replicas: 3
selector:
matchLabels:
app: hello-kubernetes-custom
template:
metadata:
labels:
app: hello-kubernetes-custom
spec:
containers:
- name: hello-kubernetes
image: paulbouwer/hello-kubernetes:1.9
ports:
- containerPort: 8080
env:
- name: MESSAGE
value: I just deployed this on Kubernetes!
- name: CONTEXT_PATH
value: "/api/v1/hello-kubernetes/"
```
### Example 3: Ingress

## Build Container Image
Deploy the `hello-kubernetes` app into the `hello-kubernetes` namespace. This example assumes that an ingress has been deployed and configured in the cluster, and that the ingress has a path of `/app/hello-kubernetes/` mapped to the `hello-kubernetes` service.

If you'd like to build the image yourself, then you can do so as follows. The `build-arg` parameters provides metadata as defined in [OCI image spec annotations](https://github.com/opencontainers/image-spec/blob/master/annotations.md).
The `hello-kubernetes` app can be reached on the ip address of the ingress via the `/app/hello-kubernetes/` path.

Bash
```bash
$ docker build --no-cache --build-arg IMAGE_VERSION="1.9" --build-arg IMAGE_CREATE_DATE="`date -u +"%Y-%m-%dT%H:%M:%SZ"`" --build-arg IMAGE_SOURCE_REVISION="`git rev-parse HEAD`" -f Dockerfile -t "hello-kubernetes:1.9" app
helm install --create-namespace --namespace hello-kubernetes ingress ./hello-kubernetes \
--set ingress.configured=true \
--set ingress.pathPrefix="/app/hello-kubernetes/" \
--set service.type="ClusterIP"
```

Powershell
```powershell
PS> docker build --no-cache --build-arg IMAGE_VERSION="1.9" --build-arg IMAGE_CREATE_DATE="$(Get-Date((Get-Date).ToUniversalTime()) -UFormat '%Y-%m-%dT%H:%M:%SZ')" --build-arg IMAGE_SOURCE_REVISION="$(git rev-parse HEAD)" -f Dockerfile -t "hello-kubernetes:1.9" app
```
## Documentation

### Deploying

If you'd like to explore the various Helm chart configuration options, then read the [Deploy with Helm](docs/deploy-using-helm.md) documentation. You can also discover more about the ingress configuration options in the [Deploy with ingress](docs/deploy-with-ingress.md) documentation

## Develop Application
### Building your own images

If you have [VS Code](https://code.visualstudio.com/) and the [Visual Studio Code Remote - Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) extension installed, the `.devcontainer` folder will be used to build a container based node.js 13 development environment.
If you'd like to build the `hello-kubernetes` container image yourself and reference from your own registry or DockerHub repository, then you can get more details on how to do this in the [Build and push container images](docs/build-and-push-container-images.md) documentation.

Port `8080` has been configured to be forwarded to your host. If you run `npm start` in the `app` folder in the VS Code Remote Containers terminal, you will be able to access the website on `http://localhost:8080`. You can change the port in the `.devcontainer\devcontainer.json` file under the `appPort` key.
### Development environment

See [here](https://code.visualstudio.com/docs/remote/containers) for more details on working with this setup.
If you have [VS Code](https://code.visualstudio.com/) and the [VS Code Remote Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) extension installed, the `.devcontainer` folder will be used to provide a container based development environment. You can read more about how to use this in the [Development environments](docs/development-environment.md) documentation.
Loading