From: Felix Pojtinger Date: Sat, 27 Apr 2019 13:49:50 +0000 (+0200) Subject: build: Minimize build time with multi-stage build, add Ingress and production versions X-Git-Url: http://these/git/%22https:/image.com/readmes/%7B%60%24%7BarchiveUrl%7D/%7B%24%7B%60data:application/manifest%20json;base64%2C%24%7Bawait?a=commitdiff_plain;h=075df62be172493cd628da0e5c09d400430ce4d7;p=lemmy.git build: Minimize build time with multi-stage build, add Ingress and production versions --- diff --git a/README.md b/README.md index 8e3db385..8b7999a5 100644 --- a/README.md +++ b/README.md @@ -11,19 +11,20 @@ A link aggregator / reddit clone for the fediverse. -[Lemmy Dev instance](https://dev.lemmy.ml) *for testing purposes only* +[Lemmy Dev instance](https://dev.lemmy.ml) _for testing purposes only_ This is a **very early beta version**, and a lot of features are currently broken or in active development, such as federation. -|Front Page|Post| -|-----------------------------------------------|----------------------------------------------- | -|![main screen](https://i.imgur.com/y64BtXC.png)|![chat screen](https://i.imgur.com/vsOr87q.png) | +| Front Page | Post | +| ----------------------------------------------- | ----------------------------------------------- | +| ![main screen](https://i.imgur.com/y64BtXC.png) | ![chat screen](https://i.imgur.com/vsOr87q.png) | ## Features - Open source, [AGPL License](/LICENSE). - Self hostable, easy to deploy. - - Comes with [docker](#docker). + - Comes with [Kubernetes](#kubernetes) + - Comes with [Docker](#docker). - Live-updating Comment threads. - Full vote scores `(+/-)` like old reddit. - Moderation abilities. @@ -56,65 +57,66 @@ Made with [Rust](https://www.rust-lang.org), [Actix](https://actix.rs/), [Infern ## Usage -### Production +### Kubernetes -#### Docker +#### Requirements -Make sure you have both docker and docker-compose installed. - -``` -git clone https://github.com/dessalines/lemmy -cd lemmy -./docker_update.sh # This pulls the newest version, builds and runs it -``` - -and goto http://localhost:8536 +- Local or remote Kubernetes cluster, i.e. [`minikube`](https://kubernetes.io/docs/tasks/tools/install-minikube/) +- [`kubectl`](https://kubernetes.io/docs/tasks/tools/install-kubectl/) +- [`skaffold`](https://skaffold.dev/) - - -### Development - -#### Kubernetes - -##### Requirements +``` -- Local or remote Kubernetes cluster, i.e. [`minikube`](https://kubernetes.io/docs/tasks/tools/install-minikube/) -- [`kubectl`](https://kubernetes.io/docs/tasks/tools/install-kubectl/) -- [`skaffold`](https://skaffold.dev/) +Now go to http://dev.lemmy.local. -##### Running +#### Development ```bash skaffold dev -p lemmy--dev ``` -And goto http://localhost:4444 (automatically proxies to localhost, both if the cluster is local or remote). +Now go to http://localhost:4444. It automatically proxies to localhost, both if the cluster is local or remote; it also hot-reloads the UI and automatically recompiles and restarts the server. + +### Docker + +Make sure you have both docker and docker-compose installed. -It hot-reloads the UI and automatically recompiles the server. +``` +git clone https://github.com/dessalines/lemmy +cd lemmy +./docker_update.sh # This pulls the newest version, builds and runs it +``` + +and goto http://localhost:8536 -#### Non-Kubernetes +### Native -##### Requirements +#### Requirements - [Rust](https://www.rust-lang.org/) - [Yarn](https://yarnpkg.com/en/) - [Postgres](https://www.sqlite.org/index.html) -##### Set up Postgres DB +#### Set up Postgres DB ``` psql -c "create user rrr with password 'rrr' superuser;" -U postgres psql -c 'create database rrr with owner rrr;' -U postgres ``` -##### Running +#### Running ``` git clone https://github.com/dessalines/lemmy diff --git a/server/Dockerfile.dev b/server/Dockerfile.dev index c7951ce8..203dd742 100644 --- a/server/Dockerfile.dev +++ b/server/Dockerfile.dev @@ -1,9 +1,7 @@ # Setup env -FROM rust:1.33 +FROM rust:1.33 AS build RUN USER=root cargo new --bin /opt/lemmy/server--dev WORKDIR /opt/lemmy/server--dev -# Create empty directory where the frontend would normally be -RUN mkdir -p /opt/lemmy/ui--dev/dist # Enable deps caching RUN mkdir -p src/bin RUN echo 'fn main() { println!("Dummy") }' >src/bin/main.rs @@ -17,5 +15,14 @@ COPY src/ src/ COPY migrations/ migrations/ RUN rm target/release/deps/lemmy* RUN cargo build --release + +# Setup env (no Alpine because Rust requires glibc) +FROM ubuntu:18.04 +RUN apt update +RUN apt install postgresql-client -y +# Create empty directory where the frontend would normally be +RUN mkdir -p /opt/lemmy/ui--dev/dist +# Add app +COPY --from=build /opt/lemmy/server--dev/target/release/lemmy . # Run app -CMD ["/opt/lemmy/server--dev/target/release/lemmy"] +CMD ["./lemmy"] diff --git a/server/Dockerfile.prod b/server/Dockerfile.prod new file mode 100644 index 00000000..b375e478 --- /dev/null +++ b/server/Dockerfile.prod @@ -0,0 +1,28 @@ +# Setup env +FROM rust:1.33 AS build +RUN USER=root cargo new --bin /opt/lemmy/server--prod +WORKDIR /opt/lemmy/server--prod +# Enable deps caching +RUN mkdir -p src/bin +RUN echo 'fn main() { println!("Dummy") }' >src/bin/main.rs +# Install deps +COPY Cargo.toml . +COPY Cargo.lock . +RUN cargo build --release +RUN rm src/bin/main.rs +# Add app +COPY src/ src/ +COPY migrations/ migrations/ +RUN rm target/release/deps/lemmy* +RUN cargo build --release + +# Setup env (no Alpine because Rust requires glibc) +FROM ubuntu:18.04 +RUN apt update +RUN apt install postgresql-client -y +# Create empty directory where the frontend would normally be +RUN mkdir -p /opt/lemmy/ui--prod/dist +# Add app +COPY --from=build /opt/lemmy/server--prod/target/release/lemmy . +# Run app +CMD ["./lemmy"] diff --git a/server/stack.prod.yaml b/server/stack.prod.yaml new file mode 100644 index 00000000..d221de16 --- /dev/null +++ b/server/stack.prod.yaml @@ -0,0 +1,110 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: postgres +data: + POSTGRES_PASSWORD: rrr + POSTGRES_USER: rrr + POSTGRES_DB: rrr + PGDATA: /var/lib/postgresql/data/pgdata + DATABASE_URL: postgres://rrr:rrr@postgres:5432/rrr +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: postgres +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 5Gi +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: postgres +spec: + selector: + matchLabels: + app: postgres + template: + metadata: + labels: + app: postgres + spec: + containers: + - name: postgres + image: postgres:11.2-alpine + resources: + limits: + memory: 256Mi + cpu: 512m + ports: + - containerPort: 5432 + envFrom: + - configMapRef: + name: postgres + volumeMounts: + - name: postgres + mountPath: /var/lib/postgresql/data + volumes: + - name: postgres + persistentVolumeClaim: + claimName: postgres +--- +apiVersion: v1 +kind: Service +metadata: + name: postgres +spec: + selector: + app: postgres + ports: + - port: 5432 +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: lemmy-server--prod +data: + LEMMY_FRONT_END_DIR: /opt/lemmy/ui--prod/dist # not actually used here, polyfill for monolith +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: lemmy-server--prod +spec: + selector: + matchLabels: + app: lemmy-server--prod + template: + metadata: + labels: + app: lemmy-server--prod + spec: + containers: + - name: lemmy-server--prod + image: registry.gitlab.com/pojntfx/lemmy/server.prod + envFrom: + - configMapRef: + name: postgres + - configMapRef: + name: lemmy-server--prod + resources: + limits: + memory: 512Mi + cpu: 512m + ports: + - containerPort: 8536 +--- +apiVersion: v1 +kind: Service +metadata: + name: lemmy-server--prod +spec: + selector: + app: lemmy-server--prod + ports: + - port: 8536 + targetPort: 8536 diff --git a/skaffold.yaml b/skaffold.yaml index 9d1d3cd7..9aeaa585 100644 --- a/skaffold.yaml +++ b/skaffold.yaml @@ -19,5 +19,19 @@ profiles: deploy: kubectl: manifests: - - server/stack.dev.yaml - - ui/stack.dev.yaml + - "**/*.dev.yaml" + - name: lemmy--prod + build: + artifacts: + - image: registry.gitlab.com/pojntfx/lemmy/server.prod + context: server + docker: + dockerfile: Dockerfile.prod + - image: registry.gitlab.com/pojntfx/lemmy/ui.prod + context: ui + docker: + dockerfile: Dockerfile.prod + deploy: + kubectl: + manifests: + - "**/*.prod.yaml" diff --git a/ui/Dockerfile.dev b/ui/Dockerfile.dev index 84ebbcad..37f9e34c 100644 --- a/ui/Dockerfile.dev +++ b/ui/Dockerfile.dev @@ -1,5 +1,5 @@ # Setup env -FROM node:10 +FROM node:10-alpine RUN mkdir -p /opt/lemmy/ui--dev WORKDIR /opt/lemmy/ui--dev # Install deps @@ -9,4 +9,4 @@ RUN npm install # Add app COPY . . # Run app -CMD npm start +CMD ["npm", "start"] diff --git a/ui/Dockerfile.prod b/ui/Dockerfile.prod new file mode 100644 index 00000000..9c478e67 --- /dev/null +++ b/ui/Dockerfile.prod @@ -0,0 +1,22 @@ +# Setup env +FROM node:10-alpine AS build +RUN mkdir -p /opt/lemmy/ui--prod +WORKDIR /opt/lemmy/ui--prod +# Install deps +COPY package.json . +COPY yarn.lock . +RUN npm install +# Add app +COPY . . +# Build app +RUN npm run build + +# Setup env +FROM node:10-alpine +RUN mkdir -p /opt/lemmy/ui--prod +WORKDIR /opt/lemmy/ui--prod +RUN npm install serve +# Add app +COPY --from=build /opt/lemmy/ui--prod/dist . +# Run app +CMD ["/opt/lemmy/ui--prod/node_modules/.bin/serve", "."] diff --git a/ui/stack.prod.yaml b/ui/stack.prod.yaml new file mode 100644 index 00000000..85ac6f6b --- /dev/null +++ b/ui/stack.prod.yaml @@ -0,0 +1,54 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: lemmy-ui--prod +spec: + selector: + matchLabels: + app: lemmy-ui--prod + template: + metadata: + labels: + app: lemmy-ui--prod + spec: + containers: + - name: lemmy-ui--prod + image: registry.gitlab.com/pojntfx/lemmy/ui.prod + resources: + limits: + memory: 1024Mi + cpu: 512m + ports: + - containerPort: 4444 +--- +apiVersion: v1 +kind: Service +metadata: + name: lemmy-ui--prod +spec: + selector: + app: lemmy-ui--prod + ports: + - port: 5000 + targetPort: 5000 +--- +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: lemmy-server--prod + annotations: + traefik.ingress.kubernetes.io/request-modifier: "ReplacePathRegex: ^/static/(.*) /$1" +spec: + rules: + - host: dev.lemmy.local + http: + paths: + - path: / + backend: + serviceName: lemmy-ui--prod + servicePort: 5000 + - path: /service/ws + backend: + serviceName: lemmy-server--prod + servicePort: 8536