Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature]: Support native deployments (without docker, includes example) #734

Closed
oddlama opened this issue Sep 22, 2022 · 9 comments
Closed
Labels
documentation Improvements or additions to documentation

Comments

@oddlama
Copy link
Contributor

oddlama commented Sep 22, 2022

Feature detail

Thanks for the great app! One thing that I'm dearly missing is the ability to deploy this on bare-metal, without relying on docker. The problem is that in certain situations, docker might not be a viable option to deploy a project. I for example am using an extremely strict nftables firewall, for which docker simply has no compatibility (and docker will likely still take some years to catch up). Furthermore, I deploy each application in its own KVM virtual machine with libvirt, so docker would just be an unnecessary overhead for me.

I have already managed to get immich running without docker just fine, it would just be missing a tiny bit of packaging to make the process more accessible and repeatable. I've attached my scripts to build and deploy immich below in case you (or any other people stumbling over this) are interested.

Installing on bare-metal

  1. Create user for immich (/var/lib/immich)
  2. Create environment file /var/lib/immich/env (adapt from upstream provided .env.example)
  3. Build app and create links to upload folder with script runuser -u immich -- ./build.sh
  4. Map container aliases to localhost in /etc/hosts like this: 127.0.0.1 localhost immich-server immich-microservices immich-machine-learning immich-web
  5. Create fstab entry to bind mount /the/backup/folder/you/want to /var/lib/immich/upload
  6. Start redis, postgresql and provided systemd services

The need to map the upload folder in several app directories is a little clunky right now, just like having to use /etc/hosts because hostnames are hardcoded. But the rest is working like a charm without docker.

You might need to change the systemd services a little to fit your system if e.g. your postgresql service is not called postgresql-14.service, or when it is running on another system. I've also used systemd to do sandboxing for the services, so they will not be able to access other directories if you need that for some reason.

Buildscript build.sh

This script is adapted from the Dockerfiles I found in this repo.

#!/bin/bash

IMMICH_TAG=v1.29.4_44-dev

set -uo pipefail
function die() { echo "error: $*" >&2; exit 1; }
function try() { "$@" || die "Command failed: $*"; }

TMP="$(mktemp --tmpdir=/var/tmp -d)" || die "Could not create tmpdir"
trap 'rm -rf -- "$TMP"' EXIT

try cd "$TMP"
try git clone https://github.com/immich-app/immich
try cd "$TMP"/immich
try git checkout "$IMMICH_TAG"

# Build server
try cd "$TMP"/immich/server
try npm ci
try npm run build
try npm prune --production
try mkdir app
try cp -a package.json package-lock.json node_modules dist app

# Build web frontend
try cd "$TMP"/immich/web
try npm ci
try npm run build
# TODO: why is the whole folder used here? Can we strip something from here? What about npm prune --production?

# Build machine-learning
try cd "$TMP"/immich/machine-learning
try npm ci
try npm rebuild @tensorflow/tfjs-node --build-from-source
try npm run build
try npm prune --production
try mkdir app
try cp -a package.json package-lock.json node_modules dist app

# Copy only relevant files to new directory
try cd "$TMP"/
try mkdir app
try mv "$TMP"/immich/server/app app/server
try mv "$TMP"/immich/web app/web
try mv "$TMP"/immich/machine-learning/app app/machine-learning

# Install new files (deleting old deployment)
[[ -e /var/lib/immich/app ]] && try rm -rf /var/lib/immich/app
try cp -r app /var/lib/immich/app

# Ensure the upload folder is available
mkdir -p /var/lib/immich/upload
ln -s /var/lib/immich/upload /var/lib/immich/app/server/upload
ln -s /var/lib/immich/upload /var/lib/immich/app/machine-learning/upload

Systemd service immich-server.service

[Unit]
Description=immich server
Documentation=https://github.com/immich-app/immich
Requires=redis-immich.service
Requires=postgresql-14.service
After=network.target
Wants=network-online.target
After=network-online.target

[Service]
User=immich
Group=immich
Type=simple
Restart=on-failure

EnvironmentFile=/var/lib/immich/env
Environment=NODE_ENV=production
SyslogIdentifier=immich-server
ExecStart=node dist/apps/immich/apps/immich/src/main

PrivateDevices=true
ProtectHome=true
ProtectSystem=strict
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes

RestrictNamespaces=yes

SystemCallArchitectures=native
AmbientCapabilities=
CapabilityBoundingSet=
NoNewPrivileges=yes

WorkingDirectory=/var/lib/immich/app/server
ReadWritePaths=/tmp /var/tmp /var/lib/immich/upload

[Install]
WantedBy=multi-user.target

Systemd service immich-microservices.service

[Unit]
Description=immich microservices
Documentation=https://github.com/immich-app/immich
Requires=redis-immich.service
Requires=postgresql-14.service
After=network.target
Wants=network-online.target
After=network-online.target

[Service]
User=immich
Group=immich
Type=simple
Restart=on-failure

EnvironmentFile=/var/lib/immich/env
Environment=NODE_ENV=production
SyslogIdentifier=immich-microservices
ExecStart=node dist/apps/microservices/apps/microservices/src/main

PrivateDevices=true
ProtectHome=true
ProtectSystem=strict
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes

RestrictNamespaces=yes

SystemCallArchitectures=native
AmbientCapabilities=
CapabilityBoundingSet=
NoNewPrivileges=yes

WorkingDirectory=/var/lib/immich/app/server
ReadWritePaths=/tmp /var/tmp /var/lib/immich/upload

[Install]
WantedBy=multi-user.target

Systemd service immich-machine-learning.service

[Unit]
Description=immich machine learning
Documentation=https://github.com/immich-app/immich
Requires=postgresql-14.service
After=network.target
Wants=network-online.target
After=network-online.target

[Service]
User=immich
Group=immich
Type=simple
Restart=on-failure

EnvironmentFile=/var/lib/immich/env
Environment=NODE_ENV=production
SyslogIdentifier=immich-machine-learning
ExecStart=node dist/main.js

PrivateDevices=true
ProtectHome=true
ProtectSystem=strict
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes

RestrictNamespaces=yes

SystemCallArchitectures=native
AmbientCapabilities=
CapabilityBoundingSet=
NoNewPrivileges=yes

WorkingDirectory=/var/lib/immich/app/machine-learning
ReadWritePaths=/tmp /var/tmp /var/lib/immich/upload

[Install]
WantedBy=multi-user.target

Systemd service immich-web.service

[Unit]
Description=immich web
Documentation=https://github.com/immich-app/immich
After=network.target
Wants=network-online.target
After=network-online.target

[Service]
User=immich
Group=immich
Type=simple
Restart=on-failure

EnvironmentFile=/var/lib/immich/env
Environment=NODE_ENV=production
SyslogIdentifier=immich-web
ExecStart=node build/index.js

PrivateDevices=true
ProtectHome=true
ProtectSystem=strict
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes

RestrictNamespaces=yes

SystemCallArchitectures=native
AmbientCapabilities=
CapabilityBoundingSet=
NoNewPrivileges=yes

WorkingDirectory=/var/lib/immich/app/web
ReadWritePaths=/tmp /var/tmp

[Install]
WantedBy=multi-user.target

P.S.: Is it intended that compiling the most recent release with npm reports 10+ high and 3 critical security issues? Not sure what to do about that as a user.

Platform

Server

@StillLoading
Copy link

Thank you for this. Really appreciate the work you put into sorting this out.

For anyone wanting to deploy on OpenSUSE Tumbleweed/MicroOS here are some pointers.

Dependencies

For building

make gcc gcc-c++ npm18 nodejs18 nodejs18-devel nodejs-common

For hosting

nginx redis postgresql-server

SELinux

Allow local nginx proxy to connect to local services via port

setsebool -P httpd_can_network_connect 1

Nginx

Grab the config from this repository and modify to your needs.

@huangfengjing
Copy link

huangfengjing commented Sep 30, 2022

Nice work.
Can anybody compose a Batch-Script/PowerShell script like this to help deploying immich on Windows?

@jumbi77
Copy link

jumbi77 commented Oct 2, 2022

Thanks a lot.
One question: Is this Requires=redis-immich.service correct in systemd.services? My system cant find those and i had to change them Requires=redis-server.service

@StillLoading
Copy link

@jumbi77 I think @oddlama did a good job at pointing that out in his post.

You might need to change the systemd services a little to fit your system if e.g. your postgresql service is not called postgresql-14.service, or when it is running on another system...

@alextran1502 alextran1502 added documentation Improvements or additions to documentation and removed need triage labels Dec 20, 2022
@alextran1502 alextran1502 pinned this issue Dec 20, 2022
@hydazz
Copy link
Contributor

hydazz commented Dec 26, 2022

(off topic)
using this installing on bare-metal method, I am creating a (hopefully) functioning single immich container for me to use on unraid (docker-compose is really messy). main issue is that the server expects hostnames immich-server immich-microservices immich-machine-learning immich-web and the hosts file cant be modified on docker so I end up with

Error: getaddrinfo ENOTFOUND immich-server

https://github.com/hydazz/docker-immich
#appsshouldbeasignecontainerwhereapplicable

edit: all seems to be working in latest commit...

@alextran1502
Copy link
Contributor

(off topic) using this installing on bare-metal method, I am creating a (hopefully) functioning single immich container for me to use on unraid (docker-compose is really messy). main issue is that the server expects hostnames immich-server immich-microservices immich-machine-learning immich-web and the hosts file cant be modified on docker so I end up with

Error: getaddrinfo ENOTFOUND immich-server

https://github.com/hydazz/docker-immich #appsshouldbeasignecontainerwhereapplicable

edit: all seems to be working in latest commit...

Thank you for the contribution.

I have a thought about your hashtag #appsshouldbeasignecontainerwhereapplicable

Let's say you want to limit the CPU of machine-learning and microservices containers which handle the intensive background tasks, so that your core server can still handle I/O operations effectively and efficiently while there are people performing backing up. Can you do that with the single container image?

@hydazz
Copy link
Contributor

hydazz commented Dec 26, 2022

Let's say you want to limit the CPU of machine-learning and microservices containers which handle the intensive background tasks, so that your core server can still handle I/O operations effectively and efficiently while there are people performing backing up. Can you do that with the single container image?

Yes, that's not really possible on a single container - there are indeed use cases for having the containers separated on lower-powered hardware. Most self-hosted image services have single containers which makes deployment much easier on specific OSes (ie Unraid), where most users won't even think about limiting the CPU of a container.

@bt90
Copy link
Contributor

bt90 commented Dec 30, 2022

You could try to start the container with the sys_nice capability and change the process priorities inside the container to accomplish that.

https://docs.docker.com/config/containers/resource_constraints/#configure-individual-containers

Pair that with e.g dumb-init:

https://github.com/Yelp/dumb-init#session-behavior

@hydazz
Copy link
Contributor

hydazz commented Dec 31, 2022

You could try to start the container with the sys_nice capability and change the process priorities inside the container to accomplish that.

https://docs.docker.com/config/containers/resource_constraints/#configure-individual-containers

Pair that with e.g dumb-init:

https://github.com/Yelp/dumb-init#session-behavior

there should be a way to achieve this with s6 and s6-overlay

Why does the machine-learning module spawn 40+ processes that use up over 1GB of ram at idle? is this necessary? is it possible to have the machine-learning run on-demand rather than all the time?
image

@immich-app immich-app locked and limited conversation to collaborators Feb 8, 2023
@alextran1502 alextran1502 converted this issue into discussion #1657 Feb 8, 2023
@michelheusschen michelheusschen unpinned this issue Mar 3, 2023

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
documentation Improvements or additions to documentation
Projects
None yet
Development

No branches or pull requests

7 participants