Skip to content

Commit d263ca0

Browse files
authored
Docker build (#354)
* Sets up working dockerized build and codex docker image creation * Making codex configurable from the docker environment * Sets up two networks with three codex nodes * enables and exposes metrics endpoint for first node * Manually performed two-client test scenario with docker containers * Sets up docker-ignore and docker github workflow * Wires up all codex CLI arguments to docker env vars * Makes API_PORT variable optional as well * Removes duplicate docker-login step * Fixes path to docker file * Switches target dockerhub for debugging * Adds git tag info to --version output * Exposes version information via debug endpoint * Debugging docker image * specifies target platforms for docker build * specifies platform for QEMU and buildx steps * Attempt to debug line endings * Disables march-native in config.nims as test * Applies make argument to disable architecture optimization during docker build * Removes subset version tags from docker build * Restore multi-arch build * Removes docker-build test branch from CI branches
1 parent 153d72c commit d263ca0

12 files changed

+335
-8
lines changed

.dockerignore

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
.github
2+
build
3+
docs
4+
metrics
5+
nimcache
6+
tests

.github/workflows/docker.yml

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
name: docker
2+
3+
on:
4+
push:
5+
branches:
6+
- "main"
7+
tags:
8+
- "v*.*.*"
9+
10+
jobs:
11+
docker:
12+
runs-on: ubuntu-latest
13+
steps:
14+
- name: Checkout
15+
uses: actions/checkout@v3
16+
- name: Docker meta
17+
id: meta
18+
uses: docker/metadata-action@v4
19+
with:
20+
images: thatbenbierens/nim-codex
21+
tags: |
22+
type=semver,pattern={{version}}
23+
type=sha
24+
- name: Set up QEMU
25+
uses: docker/setup-qemu-action@v2
26+
- name: Set up Docker Buildx
27+
uses: docker/setup-buildx-action@v2
28+
- name: Login to Docker Hub
29+
if: github.event_name != 'pull_request'
30+
uses: docker/login-action@v2
31+
with:
32+
username: ${{ secrets.DOCKERHUB_USERNAME }}
33+
password: ${{ secrets.DOCKERHUB_TOKEN }}
34+
- name: Build and push
35+
uses: docker/build-push-action@v4
36+
with:
37+
context: .
38+
file: docker/codex.Dockerfile
39+
platforms: linux/amd64,linux/arm64
40+
push: ${{ github.event_name != 'pull_request' }}
41+
tags: ${{ steps.meta.outputs.tags }}
42+
labels: ${{ steps.meta.outputs.labels }}

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,5 @@ nimble.paths
3030
.update.timestamp
3131
codex.nims
3232
nimbus-build-system.paths
33+
docker/hostdatadir
34+
docker/prometheus-data

codex/codex.nim

+1-1
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ proc new*(T: type CodexServer, config: CodexConf, privateKey: CodexPrivateKey):
173173
codexNode = CodexNodeRef.new(switch, store, engine, erasure, discovery, contracts)
174174
restServer = RestServerRef.new(
175175
codexNode.initRestApi(config),
176-
initTAddress("127.0.0.1" , config.apiPort),
176+
initTAddress(config.apiBindAddress , config.apiPort),
177177
bufferSize = (1024 * 64),
178178
maxRequestBodySize = int.high)
179179
.expect("Should start rest server!")

codex/conf.nim

+22-6
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,12 @@ type
138138
desc: "Node agent string which is used as identifier in network"
139139
name: "agent-string" }: string
140140

141+
apiBindAddress* {.
142+
desc: "The REST API bind address"
143+
defaultValue: "127.0.0.1"
144+
name: "api-bindaddr"
145+
}: string
146+
141147
apiPort* {.
142148
desc: "The REST Api port",
143149
defaultValue: 8080
@@ -195,16 +201,26 @@ type
195201

196202
EthAddress* = ethers.Address
197203

198-
const
199-
gitRevision* = strip(staticExec("git rev-parse --short HEAD"))[0..5]
204+
proc getCodexVersion(): string =
205+
let tag = strip(staticExec("git tag"))
206+
if tag.isEmptyOrWhitespace:
207+
return "untagged build"
208+
return tag
200209

201-
nimBanner* = staticExec("nim --version | grep Version")
210+
proc getCodexRevision(): string =
211+
strip(staticExec("git rev-parse --short HEAD"))[0..5]
202212

203-
#TODO add versionMajor, Minor & Fix when we switch to semver
204-
codexVersion* = gitRevision
213+
proc getNimBanner(): string =
214+
staticExec("nim --version | grep Version")
215+
216+
const
217+
codexVersion* = getCodexVersion()
218+
codexRevision* = getCodexRevision()
219+
nimBanner* = getNimBanner()
205220

206221
codexFullVersion* =
207-
"Codex build " & codexVersion & "\p" &
222+
"Codex version: " & codexVersion & "\p" &
223+
"Codex revision: " & codexRevision & "\p" &
208224
nimBanner
209225

210226
proc defaultDataDir*(): string =

codex/rest/api.nim

+5-1
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,11 @@ proc initRestApi*(node: CodexNodeRef, conf: CodexConf): RestRouter =
234234
if node.discovery.dhtRecord.isSome:
235235
node.discovery.dhtRecord.get.toURI
236236
else:
237-
""
237+
"",
238+
"codex": {
239+
"version": $codexVersion,
240+
"revision": $codexRevision
241+
}
238242
}
239243

240244
return RestApiResponse.response($json)

docker/README.md

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Codex Docker Image
2+
3+
Build and run using the example docker-compose file:
4+
`docker-compose up -d`
5+
6+
Stop and retain image and volume data:
7+
`docker-compose down`
8+
9+
Stop and delete image and volume data:
10+
`docker-compose down --rmi all -v`
11+
`rm -R hostdatadir`
12+
13+
# Environment variables
14+
Codex docker image supports the following environment variables:
15+
- LOG_LEVEL
16+
- METRICS_ADDR
17+
- METRICS_PORT
18+
- NAT_IP
19+
- API_PORT
20+
- DISC_IP
21+
- DISC_PORT
22+
- NET_PRIVKEY
23+
- BOOTSTRAP_SPR
24+
- MAX_PEERS
25+
- AGENT_STRING
26+
- STORAGE_QUOTA
27+
- BLOCK_TTL
28+
- CACHE_SIZE
29+
- ETH_PROVIDER
30+
- ETH_ACCOUNT
31+
- ETH_DEPLOYMENT
32+
33+
All environment variables are optional and will default to Codex's CLI default values.
34+
35+
# Constants
36+
Codex CLI arguments 'data-dir', 'listen-addrs', and 'api-bindaddr' cannot be configured. They are set to values required for docker in case of bind addresses. In the case of 'data-dir', the value is set to `/datadir`. It is important that you map this folder to a host volume in your container configuration. See docker-compose.yaml for examples.
37+
38+
# Useful
39+
Connect nodes with the `/connect` endpoint.
40+
To get the IP address of a container within a network:
41+
Find container Id: `docker ps`
42+
Open terminal in container: `docker exec -it <CONTAINER ID> sh`
43+
Get IP addresses: `ifconfig`

docker/codex.Dockerfile

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
FROM nimlang/nim:1.6.10-alpine AS builder
2+
WORKDIR /src
3+
RUN apk update && apk add git cmake curl make git bash linux-headers
4+
COPY . .
5+
RUN make clean
6+
RUN make update
7+
RUN make exec NIM_PARAMS="-d:disableMarchNative"
8+
9+
FROM alpine:3.17.2
10+
WORKDIR /root/
11+
RUN apk add --no-cache openssl libstdc++ libgcc libgomp
12+
COPY --from=builder /src/build/codex ./
13+
COPY --from=builder /src/docker/startCodex.sh ./
14+
CMD ["sh", "startCodex.sh"]

docker/docker-compose.yaml

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
services:
2+
codex-node1:
3+
image: clustertest-nim-codex
4+
build:
5+
context: ../.
6+
dockerfile: docker/codex.Dockerfile
7+
ports:
8+
- 8080:8080
9+
# Available environment variables:
10+
# environment:
11+
# - LOG_LEVEL=TRACE
12+
# - METRICS_ADDR=0.0.0.0
13+
# - METRICS_PORT=9090
14+
# - NAT_IP=2.3.4.5
15+
# - API_PORT=8080
16+
# - DISC_IP=3.4.5.6
17+
# - DISC_PORT=8765
18+
# - NET_PRIVKEY=privkey
19+
# - BOOTSTRAP_SPR=bootstrap_record
20+
# - MAX_PEERS=123
21+
# - AGENT_STRING=agent_string
22+
# - STORAGE_QUOTA=123456789
23+
# - BLOCK_TTL=23456
24+
# - CACHE_SIZE=6543
25+
# - ETH_PROVIDER=eth
26+
# - ETH_ACCOUNT=account
27+
# - ETH_DEPLOYMENT=deploy
28+
volumes:
29+
- ./hostdatadir/node1:/datadir
30+
networks:
31+
- primary
32+
33+
# Example with metrics enabled.
34+
codex-node2:
35+
image: clustertest-nim-codex
36+
ports:
37+
- 8081:8080
38+
- 9090:9090
39+
environment:
40+
- METRICS_ADDR=0.0.0.0
41+
- METRICS_PORT=9090
42+
volumes:
43+
- ./hostdatadir/node2:/datadir
44+
depends_on:
45+
- codex-node1
46+
networks:
47+
- primary
48+
- secondary
49+
50+
codex-node3:
51+
image: clustertest-nim-codex
52+
ports:
53+
- 8082:8080
54+
volumes:
55+
- ./hostdatadir/node3:/datadir
56+
depends_on:
57+
- codex-node1
58+
networks:
59+
- secondary
60+
61+
prometheus:
62+
image: prom/prometheus:v2.30.3
63+
ports:
64+
- 9000:9090
65+
volumes:
66+
- ./prometheus:/etc/prometheus
67+
- ./prometheus-data:/prometheus
68+
command: --web.enable-lifecycle --config.file=/etc/prometheus/prometheus.yml
69+
networks:
70+
- primary
71+
- secondary
72+
73+
networks:
74+
primary:
75+
name: primary
76+
secondary:
77+
name: secondary

docker/prometheus/alert.yml

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
groups:
2+
- name: DemoAlerts
3+
rules:
4+
- alert: InstanceDown
5+
expr: up{job="services"} < 1
6+
for: 5m

docker/prometheus/prometheus.yml

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
global:
2+
scrape_interval: 30s
3+
scrape_timeout: 10s
4+
5+
rule_files:
6+
- alert.yml
7+
8+
scrape_configs:
9+
- job_name: services
10+
metrics_path: /metrics
11+
static_configs:
12+
- targets:
13+
- 'prometheus:9090'
14+
- 'codex-node1:9090'
15+
- 'codex-node2:9090'

docker/startCodex.sh

+102
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
echo "Starting Codex..."
2+
3+
args=""
4+
5+
6+
# Required arguments
7+
args="$args --data-dir=/datadir"
8+
args="$args --listen-addrs=/ip4/0.0.0.0/tcp/8071"
9+
args="$args --api-bindaddr=0.0.0.0"
10+
11+
# Optional arguments
12+
# Log level
13+
if [ -n "$LOG_LEVEL" ]; then
14+
echo "Log level: $LOG_LEVEL"
15+
args="$args --log-level=$LOG_LEVEL"
16+
fi
17+
18+
# Metrics
19+
if [ -n "$METRICS_ADDR" ] && [ -n "$METRICS_PORT" ]; then
20+
echo "Metrics enabled"
21+
args="$args --metrics=true"
22+
args="$args --metrics-address=$METRICS_ADDR"
23+
args="$args --metrics-port=$METRICS_PORT"
24+
fi
25+
26+
# NAT
27+
if [ -n "$NAT_IP" ]; then
28+
echo "NAT: $NAT_IP"
29+
args="$args --nat=$NAT_IP"
30+
fi
31+
32+
# Discovery IP
33+
if [ -n "$DISC_IP" ]; then
34+
echo "Discovery IP: $DISC_IP"
35+
args="$args --disc-ip=$DISC_IP"
36+
fi
37+
38+
# Discovery Port
39+
if [ -n "$DISC_PORT" ]; then
40+
echo "Discovery Port: $DISC_PORT"
41+
args="$args --disc-port=$DISC_PORT"
42+
fi
43+
44+
# Net private key
45+
if [ -n "$NET_PRIVKEY" ]; then
46+
echo "Network Private Key path: $NET_PRIVKEY"
47+
args="$args --net-privkey=$NET_PRIVKEY"
48+
fi
49+
50+
# Bootstrap SPR
51+
if [ -n "$BOOTSTRAP_SPR" ]; then
52+
echo "Bootstrap SPR: $BOOTSTRAP_SPR"
53+
args="$args --bootstrap-node=$BOOTSTRAP_SPR"
54+
fi
55+
56+
# Max peers
57+
if [ -n "$MAX_PEERS" ]; then
58+
echo "Max peers: $MAX_PEERS"
59+
args="$args --max-peers=$MAX_PEERS"
60+
fi
61+
62+
# Agent string
63+
if [ -n "$AGENT_STRING" ]; then
64+
echo "Agent string: $AGENT_STRING"
65+
args="$args --agent-string=$AGENT_STRING"
66+
fi
67+
68+
# API port
69+
if [ -n "$API_PORT" ]; then
70+
echo "API port: $API_PORT"
71+
args="$args --api-port=$API_PORT"
72+
fi
73+
74+
# Storage quota
75+
if [ -n "$STORAGE_QUOTA" ]; then
76+
echo "Storage quote: $STORAGE_QUOTA"
77+
args="$args --storage-quota=$STORAGE_QUOTA"
78+
fi
79+
80+
# Block TTL
81+
if [ -n "$BLOCK_TTL" ]; then
82+
echo "Block TTL: $BLOCK_TTL"
83+
args="$args --block-ttl=$BLOCK_TTL"
84+
fi
85+
86+
# Cache size
87+
if [ -n "$CACHE_SIZE" ]; then
88+
echo "Cache size: $CACHE_SIZE"
89+
args="$args --cache-size=$CACHE_SIZE"
90+
fi
91+
92+
# Ethereum persistence
93+
if [ -n "$ETH_PROVIDER" ] && [ -n "$ETH_ACCOUNT" ] && [ -n "$ETH_DEPLOYMENT" ]; then
94+
echo "Persistence enabled"
95+
args="$args --persistence=true"
96+
args="$args --eth-provider=$ETH_PROVIDER"
97+
args="$args --eth-account=$ETH_ACCOUNT"
98+
args="$args --eth-deployment=$ETH_DEPLOYMENT"
99+
fi
100+
101+
echo "./root/codex $args"
102+
sh -c "/root/codex $args"

0 commit comments

Comments
 (0)