1 Commits

Author SHA1 Message Date
29980517f6 publish experimental apparatus plugin 2017-12-18 22:53:02 -07:00
10 changed files with 181 additions and 363 deletions

View File

@ -1,17 +1,20 @@
FROM node:lts-alpine
FROM node:8-slim
RUN apk add --update --no-cache \
dumb-init \
git \
jq
WORKDIR "/home/node"
ARG WIKI_PACKAGE=wiki@0.28.0
RUN su node -c "npm install -g --prefix . $WIKI_PACKAGE"
RUN su node -c "mkdir -p .wiki"
VOLUME "/home/node/.wiki"
RUN useradd --create-home app \
&& apt-get update \
&& apt-get install -y --no-install-recommends \
jq \
git
WORKDIR /home/app
ARG WIKI_PACKAGE='dobbs/wiki#apparatus'
RUN su app -c "npm install -g --prefix . $WIKI_PACKAGE"
RUN su app -c "mkdir .wiki"
COPY configure-and-launch-wiki set-owner-name ./
RUN chown app configure-and-launch-wiki set-owner-name
VOLUME "/home/app/.wiki"
ENV DOMAIN=localhost
ENV OWNER_NAME="The Owner"
ENV COOKIE=insecure
EXPOSE 3000
USER node
ENV PATH="${PATH}:/home/node/bin"
ENV NPM_CONFIG_PREFIX="${HOME}"
ENTRYPOINT ["dumb-init"]
CMD ["wiki", "--farm", "--security_type=friends"]
USER app
CMD ["./configure-and-launch-wiki"]

View File

@ -1,56 +1,62 @@
# Federated Wiki Farm
Start Playing Federated Wiki: http://start.fed.wiki
http://fed.wiki.org
### Run a local wiki farm
### Get acquainted with wiki.
docker run -p 3000:3000 -it --rm \
dobbs/farm
Launch the container:
``` bash
docker run -p 3000:3000 -it --rm \
dobbs/farm
```
Visit http://localhost:3000 and http://anything.localhost:3000
Visit http://localhost:3000
### Run a local wiki that will survive a reboot
### Make your wiki survive a reboot
docker run -p 3000:3000 -it --rm \
-v ~/.wiki:/home/node/.wiki \
dobbs/farm
Create a volume:
Your wiki pages and configuration will be saved in the ~/.wiki folder.
``` bash
docker volume create dot-wiki
```
Launch the container:
``` bash
docker run -p 3000:3000 -it --rm \
-v dot-wiki:/home/app/.wiki \
dobbs/farm
```
Visit http://localhost:3000
### Make your wiki a local farm
We're going to use http://localtest.me instead of localhost for our
domain name. See http://readme.localtest.me for more info.
Let's also use a different volume for this one:
``` bash
docker volume create localtest.me
```
Specify the domain name when you launch your wiki
``` bash
docker run -p 3000:3000 -it --rm \
-v localtest.me:/home/app/.wiki \
-e DOMAIN=localtest.me \
dobbs/farm
```
Open http://this.localtest.me:3000 in one tab.
Open http://that.localtest.me:3000 in another.
# Development
This image's tag does not match the version of the included wiki
software. Our version indicates the scale of changes in this tiny
devops pipeline.
Testing new images locally:
This image's tag matches the version of the included wiki software.
``` bash
TAG=1.0.8-prefer-title
IMAGE=dobbs/farm:$TAG
docker build --tag $IMAGE .
git tag -am "" '0.13.0'
git push --tags
```
With the local kubernetes example (see [examples/k8s/README.md](./examples/k8s/README.md)):
``` bash
k3d image import $IMAGE --cluster wiki
kubectl patch deployment.apps/wiki-deployment \
--type='json' \
-p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"'$IMAGE'"}]'
```
# Publish containers
GitHub
``` bash
git tag -am "" "$TAG"
git push --atomic origin main "$TAG"
```
Docker Hub
``` bash
docker push $IMAGE
docker push dobbs/farm:latest
```
The repos in Dockerhub and GitHub are configured to automatically build new tags.

View File

@ -1,15 +0,0 @@
# Release Notes for 1.0.0
This is a significant **breaking** change from pre-1.0 releases. Especially:
* changed the user from `app` (`uid=1001(app) gid=1001(app) groups=1001(app)`)
to `node` (`uid=1000(node) gid=1000(node) groups=1000(node),1000(node)`)
* no longer installing `bash`, `configure-wiki`, nor `set-owner-name`
* no longer creating `/home/app/.wiki/wiki.json`
Those changes in particular will impose some work on authors upgrading
from previous versions.
The last non-breaking revision is 0.52.0 https://github.com/dobbs/farm/tree/0.52.0#readme

77
configure-and-launch-wiki Executable file
View File

@ -0,0 +1,77 @@
#!/bin/bash -eu
set -o pipefail
main() {
initialize-environment-vars
assert-file-privileges || report-errors-and-exit
ensure-owner-file
ensure-config-file
show-configs
exec-wiki
}
initialize-environment-vars() {
ERRORS=''
readonly OWNER_FILE=/home/app/.wiki/$DOMAIN.owner.json
readonly CONFIG_FILE=/home/app/.wiki/config.json
}
assert-file-privileges() {
[ -w /home/app/.wiki ] \
|| ERRORS="app cannot write to /home/app/.wiki\n${ERRORS}"
[ ${#ERRORS} == 0 ]
}
report-errors-and-exit() {
echo -e $ERRORS
echo "exiting."
exit 1
}
ensure-owner-file() {
if [ ! -r "$OWNER_FILE" ]; then
jq -n --arg name "$OWNER_NAME" --arg secret $(random-string) \
'.name = $name | .friend.secret = $secret' > $OWNER_FILE
fi
}
ensure-config-file() {
if [ ! -r "$CONFIG_FILE" ]; then
> $CONFIG_FILE \
jq -n -M \
--arg admin $(jq -r .friend.secret $OWNER_FILE) \
--arg random $(random-string) \
--arg cookie $COOKIE \
--arg domain $DOMAIN \
--arg owner $OWNER_FILE \
'
.admin = $admin
| .autoseed = true
| .farm = true
| .cookieSecret = $random
| .secure_cookie = ("secure" == $cookie)
| .security_type = "friends"
| .wikiDomains[$domain].id = "/home/app/.wiki/\($domain).owner.json"
'
fi
}
random-string() {
node -e 'console.log(require("crypto").randomBytes(64).toString("hex"))'
}
show-configs() {
set -x
ls -l $OWNER_FILE $CONFIG_FILE
cat $OWNER_FILE
cat $CONFIG_FILE
set +x
}
exec-wiki() {
exec /home/app/bin/wiki
}
main

View File

@ -1,56 +0,0 @@
# Wiki Farm in Kubernetes
There are easier ways to get started with federated wiki. Here we are
using wiki to drive some learning about kubernetes.
# We're using MacOS, Docker Desktop, and k3d
brew install --cask docker
brew install k3d
mkdir -p ~/.wiki-k8s ~/workspace/fedwiki
k3d create \
--server-arg --tls-san="127.0.0.1" \
--publish 80:80 \
-v "$HOME/.wiki-k8s:/macos/.wiki-k8s" \
-v "$HOME/workspace/fedwiki:/macos/fedwiki" \
--name wiki
# example ~/.wiki-k8s/config.json
{
"admin": "any memorable password",
"autoseed": true,
"farm": true,
"cookieSecret": "any random string",
"secure_cookie": false,
"security_type": "friends",
"wikiDomains": {
"localhost": {
"id": "/home/node/.wiki/localhost.owner.json"
},
"example.com": {
"id": "/home/node/.wiki/example.com.owner.json"
}
}
}
# example ~/.wiki-k8s/localhost.owner.json
`.friend.secret` must match the `.admin` field from `config.json`
{
"name": "The Owner",
"friend": {
"secret": "any memorable password"
}
}
# Deploy Wiki
kubectl apply -f http://deploy.wiki.do/assets/wiki/wiki.yaml
# Play with the wiki
open http://wiki.localhost

View File

@ -1,29 +0,0 @@
# HashiCorp Vault in kubernetes
HashiCorp recomend installing vault via helm. Your author prefers
plain old kubernetes configs.
So we generated the yaml via helm's template command.
helm template incubator/vault \
--name-template=vault \
--replicaCount=1 \
--set vault.dev=false \
--set vault.config.storage.file.path=/macos/.wiki-k8s/vault \
| egrep -v 'heritage: "?Helm"?' \
> vault.html
kubectl apply -k .
kubectl port-forward svc/vault 8200:8200 &> /dev/null &
export VAULT_ADDR=http://127.0.0.1:8200
vault status
vault operator init
vault operator unseal
# paste key-fragment 1
vault operator unseal
# paste key-fragment 2
vault operator unseal
# paste key-fragment 3
vault login
# paste root token

View File

@ -1,16 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: vault
spec:
template:
spec:
containers:
- name: vault
volumeMounts:
- name: vault-data
mountPath: /macos/.wiki-k8s/vault
volumes:
- name: vault-data
hostPath:
path: /macos/.wiki-k8s/vault

View File

@ -1,10 +0,0 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
images:
- name: vault
newName: vault
newTag: 1.3.1
resources:
- vault.yaml
patchesStrategicMerge:
- deployment-volumes.yaml

View File

@ -1,181 +0,0 @@
---
# Source: vault/templates/clusterrolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: vault
labels:
app: vault
release: "vault"
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:auth-delegator
subjects:
- kind: ServiceAccount
name: vault
namespace: default
---
# Source: vault/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: "vault-config"
labels:
app: "vault"
release: "vault"
data:
config.json: |
{"listener":{"tcp":{"address":"[::]:8200","cluster_address":"[::]:8201","tls_disable":true}},"storage":{"file":{"path":"/macos/.wiki-k8s/vault"}}}
---
# Source: vault/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: vault
labels:
app: vault
release: vault
annotations:
{}
spec:
selector:
matchLabels:
app: vault
release: vault
replicas: 1
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
template:
metadata:
labels:
app: vault
release: vault
annotations:
checksum/config: 6868eb00aa48ca9485c365c3523ae431e7031233a1c046817a32c61e24ea817d
spec:
containers:
- name: vault
image: "vault:1.2.3"
imagePullPolicy: IfNotPresent
command: ["vault", "server", "-config", "/vault/config/config.json"]
ports:
- containerPort: 8200
name: api
- containerPort: 8201
name: cluster-address
livenessProbe:
# Alive if Vault is successfully responding to requests
httpGet:
path: /v1/sys/health?standbyok=true&uninitcode=204&sealedcode=204&
port: 8200
scheme: HTTP
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
# Ready depends on preference
httpGet:
path: /v1/sys/health?standbycode=204&uninitcode=204&
port: 8200
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
securityContext:
readOnlyRootFilesystem: true
capabilities:
add:
- IPC_LOCK
env:
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: VAULT_API_ADDR
value: "http://$(POD_IP):8200"
- name: VAULT_CLUSTER_ADDR
value: "https://$(POD_IP):8201"
- name: VAULT_LOG_LEVEL
value: "info"
resources:
{}
volumeMounts:
- name: vault-config
mountPath: /vault/config/
- name: vault-root
mountPath: /root/
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- podAffinityTerm:
labelSelector:
matchLabels:
app: 'vault'
release: 'vault'
topologyKey: kubernetes.io/hostname
weight: 100
serviceAccountName: vault
volumes:
- name: vault-config
configMap:
name: "vault-config"
- name: vault-root
emptyDir: {}
---
# Source: vault/templates/pdb.yaml
apiVersion: policy/v1beta1
kind: PodDisruptionBudget
metadata:
name: vault
spec:
maxUnavailable: 1
selector:
matchLabels:
app: vault
release: vault
---
# Source: vault/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: vault
labels:
app: vault
release: vault
spec:
type: ClusterIP
ports:
- port: 8200
protocol: TCP
targetPort: 8200
name: api
selector:
app: vault
release: vault
---
# Source: vault/templates/serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: vault
labels:
app: vault
release: "vault"
---
# Source: vault/templates/tests/test-vault-status.yaml
apiVersion: v1
kind: Pod
metadata:
name: "vault-vault-status-test"
annotations:
"helm.sh/hook": test-success
spec:
containers:
- name: vault-vault-status-test
image: "vault:1.2.3"
env:
- name: VAULT_ADDR
value: http://vault.default:8200
command: ["sh", "-c", "vault status"]
restartPolicy: Never

39
set-owner-name Executable file
View File

@ -0,0 +1,39 @@
#!/bin/bash -eu
set -o pipefail
usage() {
cat <<EOF
Usage: $(basename $0) NAME
replaces the owner's name in $OWNER_FILE
EOF
}
main() {
initialize-environment-vars $@ || { usage; exit 1; }
backup-and-save-name
report-success
}
initialize-environment-vars() {
readonly OWNER_FILE=/home/app/.wiki/$DOMAIN.owner.json
readonly OWNER_BACKUP_FILE=$OWNER_FILE-saved-$(date --iso-8601=minutes)
readonly NAME=${@:-missing}
[ ! "$NAME" == "missing" ]
}
backup-and-save-name() {
mv $OWNER_FILE $OWNER_BACKUP_FILE
jq ".name = \"$NAME\"" $OWNER_BACKUP_FILE > $OWNER_FILE
}
report-success() {
cat <<EOF
Owner's name changed to "$NAME"
Previous config is saved in ${OWNER_BACKUP_FILE##$PWD/}
EOF
}
main "$@"