Skip to content

Commit

Permalink
feat: add docker files (#1418)
Browse files Browse the repository at this point in the history
* Add docker files

* Add python precompiled cache file in the image

* Add Notes in docker.md

* Create docker-publish.yml

* Modify docker-compose.yml not to use the bind mount

* Update torch version

* Change --share to --listen

* Update torch version

* Change '--share' to '--listen`

* adjust code comments

* Update requirements-docker.txt

* chore: code cleanup

- default_model env var isn't necessary as model is included in default preset, same for speed
- ENV CMDARGS --listen is now synched with docker-compose.yml file
- remove

* Change entry_with_update.py to launch.py in entrypoint.sh

* Change CMD in Dockerfile

* Change default CMDARGS to --listen in Dockerfile

* Modify CMD in Dockerfile

* Fix docker-compose.yml

* Import files from models,outputs

* docs: change wording in docker.md, change git clone URL, add quotes to port mapping

* docs: remove docker publish github action, remove pre-built image from docs

* Modify modules versions for linux/arm64

* docs: update docker readme

---------

Co-authored-by: Manuel Schmid <[email protected]>
Co-authored-by: Manuel Schmid <[email protected]>
Co-authored-by: Manuel Schmid <[email protected]>
  • Loading branch information
4 people authored Feb 26, 2024
1 parent b6d2367 commit f4a6350
Show file tree
Hide file tree
Showing 9 changed files with 198 additions and 5 deletions.
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.idea
29 changes: 29 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
FROM nvidia/cuda:12.3.1-base-ubuntu22.04
ENV DEBIAN_FRONTEND noninteractive
ENV CMDARGS --listen

RUN apt-get update -y && \
apt-get install -y curl libgl1 libglib2.0-0 python3-pip python-is-python3 git && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*

COPY requirements_docker.txt requirements_versions.txt /tmp/
RUN pip install --no-cache-dir -r /tmp/requirements_docker.txt -r /tmp/requirements_versions.txt && \
rm -f /tmp/requirements_docker.txt /tmp/requirements_versions.txt
RUN pip install --no-cache-dir xformers==0.0.22 --no-dependencies
RUN curl -fsL -o /usr/local/lib/python3.10/dist-packages/gradio/frpc_linux_amd64_v0.2 https://cdn-media.huggingface.co/frpc-gradio-0.2/frpc_linux_amd64 && \
chmod +x /usr/local/lib/python3.10/dist-packages/gradio/frpc_linux_amd64_v0.2

RUN adduser --disabled-password --gecos '' user && \
mkdir -p /content/app /content/data

COPY entrypoint.sh /content/
RUN chown -R user:user /content

WORKDIR /content
USER user

RUN git clone https://github.com/lllyasviel/Fooocus /content/app
RUN mv /content/app/models /content/app/models.org

CMD [ "sh", "-c", "/content/entrypoint.sh ${CMDARGS}" ]
38 changes: 38 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
version: '3.9'

volumes:
fooocus-data:

services:
app:
build: .
image: fooocus
ports:
- "7865:7865"
environment:
- CMDARGS=--listen # Arguments for launch.py.
- DATADIR=/content/data # Directory which stores models, outputs dir
- config_path=/content/data/config.txt
- config_example_path=/content/data/config_modification_tutorial.txt
- path_checkpoints=/content/data/models/checkpoints/
- path_loras=/content/data/models/loras/
- path_embeddings=/content/data/models/embeddings/
- path_vae_approx=/content/data/models/vae_approx/
- path_upscale_models=/content/data/models/upscale_models/
- path_inpaint=/content/data/models/inpaint/
- path_controlnet=/content/data/models/controlnet/
- path_clip_vision=/content/data/models/clip_vision/
- path_fooocus_expansion=/content/data/models/prompt_expansion/fooocus_expansion/
- path_outputs=/content/app/outputs/ # Warning: If it is not located under '/content/app', you can't see history log!
volumes:
- fooocus-data:/content/data
#- ./models:/import/models # Once you import files, you don't need to mount again.
#- ./outputs:/import/outputs # Once you import files, you don't need to mount again.
tty: true
deploy:
resources:
reservations:
devices:
- driver: nvidia
device_ids: ['0']
capabilities: [compute, utility]
66 changes: 66 additions & 0 deletions docker.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Fooocus on Docker

The docker image is based on NVIDIA CUDA 12.3 and PyTorch 2.0, see [Dockerfile](Dockerfile) and [requirements_docker.txt](requirements_docker.txt) for details.

## Quick start

**This is just an easy way for testing. Please find more information in the [notes](#notes).**

1. Clone this repository
2. Build the image with `docker compose build`
3. Run the docker container with `docker compose up`. Building the image takes some time.

When you see the message `Use the app with http://0.0.0.0:7865/` in the console, you can access the URL in your browser.

Your models and outputs are stored in the `fooocus-data` volume, which, depending on OS, is stored in `/var/lib/docker/volumes`.

## Details

### Update the container manually

When you are using `docker compose up` continuously, the container is not updated to the latest version of Fooocus automatically.
Run `git pull` before executing `docker compose build --no-cache` to build an image with the latest Fooocus version.
You can then start it with `docker compose up`

### Import models, outputs
If you want to import files from models or the outputs folder, you can uncomment the following settings in the [docker-compose.yml](docker-compose.yml):
```
#- ./models:/import/models # Once you import files, you don't need to mount again.
#- ./outputs:/import/outputs # Once you import files, you don't need to mount again.
```
After running `docker compose up`, your files will be copied into `/content/data/models` and `/content/data/outputs`
Since `/content/data` is a persistent volume folder, your files will be persisted even when you re-run `docker compose up --build` without above volume settings.


### Paths inside the container

|Path|Details|
|-|-|
|/content/app|The application stored folder|
|/content/app/models.org|Original 'models' folder.<br> Files are copied to the '/content/app/models' which is symlinked to '/content/data/models' every time the container boots. (Existing files will not be overwritten.) |
|/content/data|Persistent volume mount point|
|/content/data/models|The folder is symlinked to '/content/app/models'|
|/content/data/outputs|The folder is symlinked to '/content/app/outputs'|

### Environments

You can change `config.txt` parameters by using environment variables.
**The priority of using the environments is higher than the values defined in `config.txt`, and they will be saved to the `config_modification_tutorial.txt`**

Docker specified environments are there. They are used by 'entrypoint.sh'
|Environment|Details|
|-|-|
|DATADIR|'/content/data' location.|
|CMDARGS|Arguments for [entry_with_update.py](entry_with_update.py) which is called by [entrypoint.sh](entrypoint.sh)|
|config_path|'config.txt' location|
|config_example_path|'config_modification_tutorial.txt' location|

You can also use the same json key names and values explained in the 'config_modification_tutorial.txt' as the environments.
See examples in the [docker-compose.yml](docker-compose.yml)

## Notes

- Please keep 'path_outputs' under '/content/app'. Otherwise, you may get an error when you open the history log.
- Docker on Mac/Windows still has issues in the form of slow volume access when you use "bind mount" volumes. Please refer to [this article](https://docs.docker.com/storage/volumes/#use-a-volume-with-docker-compose) for not using "bind mount".
- The MPS backend (Metal Performance Shaders, Apple Silicon M1/M2/etc.) is not yet supported in Docker, see https://github.com/pytorch/pytorch/issues/81224
- You can also use `docker compose up -d` to start the container detached and connect to the logs with `docker compose logs -f`. This way you can also close the terminal and keep the container running.
33 changes: 33 additions & 0 deletions entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/bin/bash

ORIGINALDIR=/content/app
# Use predefined DATADIR if it is defined
[[ x"${DATADIR}" == "x" ]] && DATADIR=/content/data

# Make persistent dir from original dir
function mklink () {
mkdir -p $DATADIR/$1
ln -s $DATADIR/$1 $ORIGINALDIR
}

# Copy old files from import dir
function import () {
(test -d /import/$1 && cd /import/$1 && cp -Rpn . $DATADIR/$1/)
}

cd $ORIGINALDIR

# models
mklink models
# Copy original files
(cd $ORIGINALDIR/models.org && cp -Rpn . $ORIGINALDIR/models/)
# Import old files
import models

# outputs
mklink outputs
# Import old files
import outputs

# Start application
python launch.py $*
25 changes: 21 additions & 4 deletions modules/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,16 @@
from modules.util import get_files_from_folder, makedirs_with_log
from modules.flags import Performance, MetadataScheme

config_path = os.path.abspath("./config.txt")
config_example_path = os.path.abspath("config_modification_tutorial.txt")
def get_config_path(key, default_value):
env = os.getenv(key)
if env is not None and isinstance(env, str):
print(f"Environment: {key} = {env}")
return env
else:
return os.path.abspath(default_value)

config_path = get_config_path('config_path', "./config.txt")
config_example_path = get_config_path('config_example_path', "config_modification_tutorial.txt")
config_dict = {}
always_save_keys = []
visited_keys = []
Expand Down Expand Up @@ -123,7 +131,12 @@ def get_dir_or_set_default(key, default_value, as_array=False, make_directory=Fa
if key not in always_save_keys:
always_save_keys.append(key)

v = config_dict.get(key, None)
v = os.getenv(key)
if v is not None:
print(f"Environment: {key} = {v}")
config_dict[key] = v
else:
v = config_dict.get(key, None)

if isinstance(v, str):
if make_directory:
Expand Down Expand Up @@ -165,13 +178,17 @@ def get_dir_or_set_default(key, default_value, as_array=False, make_directory=Fa
path_fooocus_expansion = get_dir_or_set_default('path_fooocus_expansion', '../models/prompt_expansion/fooocus_expansion')
path_outputs = get_path_output()


def get_config_item_or_set_default(key, default_value, validator, disable_empty_as_none=False):
global config_dict, visited_keys

if key not in visited_keys:
visited_keys.append(key)

v = os.getenv(key)
if v is not None:
print(f"Environment: {key} = {v}")
config_dict[key] = v

if key not in config_dict:
config_dict[key] = default_value
return default_value
Expand Down
2 changes: 1 addition & 1 deletion modules/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ def generate_temp_filename(folder='./outputs/', extension='png'):
random_number = random.randint(1000, 9999)
filename = f"{time_string}_{random_number}.{extension}"
result = os.path.join(folder, date_string, filename)
return date_string, os.path.abspath(os.path.realpath(result)), filename
return date_string, os.path.abspath(result), filename


def get_files_from_folder(folder_path, exensions=None, name_filter=None):
Expand Down
4 changes: 4 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,10 @@ You can install Fooocus on Apple Mac silicon (M1 or M2) with macOS 'Catalina' or

Use `python entry_with_update.py --preset anime` or `python entry_with_update.py --preset realistic` for Fooocus Anime/Realistic Edition.

### Docker

See [docker.md](docker.md)

### Download Previous Version

See the guidelines [here](https://github.com/lllyasviel/Fooocus/discussions/1405).
Expand Down
5 changes: 5 additions & 0 deletions requirements_docker.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
torch==2.0.1
torchvision==0.15.2
torchaudio==2.0.2
torchtext==0.15.2
torchdata==0.6.1

0 comments on commit f4a6350

Please sign in to comment.