feat(comfyui): add Dockerfile, playbook, and Terraform configurations for ComfyUI setup
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
# Use NVIDIA's PyTorch image with CUDA support
|
||||
FROM docker.io/pytorch/pytorch:2.1.0-cuda11.8-cudnn8-runtime
|
||||
|
||||
# Set environment variables
|
||||
ENV PYTHONDONTWRITEBYTECODE=1
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
|
||||
# Install system dependencies
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
RUN apt-get update && \
|
||||
apt-get install -y tzdata git ffmpeg libgl1 libglib2.0-0 && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ARG UID=1000
|
||||
ARG GID=1000
|
||||
RUN groupadd --system --gid ${GID} worker && \
|
||||
adduser --system --gid ${GID} --uid ${UID} --home /home/worker worker
|
||||
|
||||
WORKDIR /home/worker
|
||||
USER worker
|
||||
|
||||
# Clone ComfyUI
|
||||
RUN git clone https://github.com/comfyanonymous/ComfyUI.git .
|
||||
|
||||
# Install Python dependencies
|
||||
RUN pip install --upgrade pip && \
|
||||
pip install -r requirements.txt && \
|
||||
rm -rf /home/worker/.cache/pip
|
||||
|
||||
# Expose port
|
||||
EXPOSE 8188
|
||||
|
||||
# Run ComfyUI
|
||||
CMD ["python", "main.py", "--listen", "0.0.0.0", "--port", "8188"]
|
||||
|
||||
@@ -40,7 +40,8 @@ fw_allowed_ports:
|
||||
- { rule: "allow", port: "11434", proto: "tcp", from: "10.19.4.0/24" } # Ollama (local network)
|
||||
- { rule: "allow", port: "11434", proto: "tcp", from: "10.5.5.5/32" } # Ollama (Laptop)
|
||||
- { rule: "allow", port: "8880", proto: "tcp", from: "10.19.4.0/24" } # Kokoro-FastAPI (local network)
|
||||
|
||||
- { rule: "allow", port: "8188", proto: "tcp", from: "10.19.4.0/24" } # ComfyUI (local network)
|
||||
- { rule: "allow", port: "8999", proto: "tcp", from: "10.19.4.0/24" } # ComfyUI - SimpleHttpServer (local network)
|
||||
ufw_outgoing_traffic:
|
||||
- 22 # SSH
|
||||
- 53 # DNS
|
||||
@@ -70,9 +71,16 @@ unattended_reboot: true
|
||||
unattended_reboot_time: "04:30"
|
||||
|
||||
# Duo Security
|
||||
duo_users: ["*", "!provision"]
|
||||
duo_users: ["*", "!provision", "!comfyui", "!kokoro", "!ollama"]
|
||||
duo_api_hostname: api-7cda1654.duosecurity.com
|
||||
|
||||
# podman services settings
|
||||
ollama_home: "/mnt/data/ollama"
|
||||
kokora_home: "/mnt/data/kokoro"
|
||||
podman_user_pubkey: "ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAHHOPBR9p9kq5Cqzpe4cr3jHnweaYrHPXv5sXNzt+sCXP54uc5rWUBhxW2OQVvQzJ47dEVhEKi4WSC7LcuKS2G5AQDzWXNiasHvYIYQU3F/EknVCZnsiXYqXphYkJA6rJCNRnISZCIC1mocq6PB7J08ONdRFCvjfUBuVRT8BNGXNmQ/zQ=="
|
||||
|
||||
# ComfyUI settings
|
||||
comfyui_home: "/mnt/data/comfyui"
|
||||
comfyui_user_pubkey: "ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAHHOPBR9p9kq5Cqzpe4cr3jHnweaYrHPXv5sXNzt+sCXP54uc5rWUBhxW2OQVvQzJ47dEVhEKi4WSC7LcuKS2G5AQDzWXNiasHvYIYQU3F/EknVCZnsiXYqXphYkJA6rJCNRnISZCIC1mocq6PB7J08ONdRFCvjfUBuVRT8BNGXNmQ/zQ=="
|
||||
|
||||
# Kokoro FastAPI settings (we don't set home because it is not expected to use a lot a disk space)
|
||||
kokoro_user_pubkey: "ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAHHOPBR9p9kq5Cqzpe4cr3jHnweaYrHPXv5sXNzt+sCXP54uc5rWUBhxW2OQVvQzJ47dEVhEKi4WSC7LcuKS2G5AQDzWXNiasHvYIYQU3F/EknVCZnsiXYqXphYkJA6rJCNRnISZCIC1mocq6PB7J08ONdRFCvjfUBuVRT8BNGXNmQ/zQ=="
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
- name: Setup ComfyUI
|
||||
hosts: comfyui
|
||||
vars:
|
||||
podman_user: "{{ comfyui_user | default('comfyui') }}"
|
||||
podman_group: "{{ comfyui_group | default('comfyui') }}"
|
||||
podman_user_home: "{{ comfyui_home | default('/home/comfyui') }}"
|
||||
podman_extra_groups: "users"
|
||||
podman_user_pubkey: "{{ comfyui_user_pubkey | default(omit) }}"
|
||||
podman_user_folders:
|
||||
- models
|
||||
- models/checkpoints
|
||||
- models/clip
|
||||
- models/clip_vision
|
||||
- models/configs
|
||||
- models/controlnet
|
||||
- models/diffusers
|
||||
- models/diffusion_models
|
||||
- models/embeddings
|
||||
- models/gligen
|
||||
- models/hypernetworks
|
||||
- models/loras
|
||||
- models/photomaker
|
||||
- models/style_models
|
||||
- models/text_encoders
|
||||
- models/unet
|
||||
- models/upscale_models
|
||||
- models/vae
|
||||
- models/vae_approx
|
||||
- output
|
||||
- custom_nodes
|
||||
- .cache
|
||||
pods:
|
||||
- name: comfyui
|
||||
build:
|
||||
dockerfile: "{{ lookup('file', 'dockerfiles/Dockerfile.comfyui') }}"
|
||||
ports:
|
||||
- "0.0.0.0:{{ comfyui_port | default(8188) }}:8188/tcp"
|
||||
env:
|
||||
PYTORCH_CUDA_ALLOC_CONF: max_split_size_mb:512
|
||||
volumes:
|
||||
- "{{ podman_user_home }}/.cache:/home/worker/.cache:Z"
|
||||
- "{{ podman_user_home }}/models:/home/worker/models:Z"
|
||||
- "{{ podman_user_home }}/custom_nodes:/home/worker/custom_nodes:Z"
|
||||
- "{{ podman_user_home }}/output:/home/worker/output:Z"
|
||||
device:
|
||||
- "nvidia.com/gpu=all"
|
||||
systemd:
|
||||
enabled: false
|
||||
state: "stopped"
|
||||
|
||||
tasks:
|
||||
- name: Setup nvidia-cdi-generator
|
||||
ansible.builtin.include_tasks:
|
||||
file: tasks/nvidia-cdi-generator.yml
|
||||
|
||||
- name: Setup Pods
|
||||
ansible.builtin.include_tasks:
|
||||
file: tasks/podman.yml
|
||||
@@ -3,7 +3,9 @@
|
||||
vars:
|
||||
podman_user: "{{ kokoro_user | default('kokoro') }}"
|
||||
podman_group: "{{ kokoro_group | default('kokoro') }}"
|
||||
podman_extra_groups: "users"
|
||||
podman_user_home: "{{ kokoro_home | default('/home/kokoro') }}"
|
||||
podman_user_pubkey: "{{ kokoro_user_pubkey | default(omit) }}"
|
||||
podman_user_folders:
|
||||
- data
|
||||
pods:
|
||||
@@ -16,6 +18,10 @@
|
||||
- "nvidia.com/gpu=all"
|
||||
|
||||
tasks:
|
||||
- name: Setup nvidia-cdi-generator
|
||||
ansible.builtin.include_tasks:
|
||||
file: tasks/nvidia-cdi-generator.yml
|
||||
|
||||
- name: Setup Pods
|
||||
ansible.builtin.include_tasks:
|
||||
file: tasks/podman.yml
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
- name: Setup MCP servers
|
||||
hosts: mcp
|
||||
vars:
|
||||
podman_user: "{{ mcp_user | default('mcp') }}"
|
||||
podman_group: "{{ mcp_group | default('mcp') }}"
|
||||
podman_user_home: "{{ mcp_home | default('/home/mcp') }}"
|
||||
mcp_servers:
|
||||
- name: gitea-mcp
|
||||
enabled: false
|
||||
build:
|
||||
super_user_custom_actions: |
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
curl \
|
||||
tar \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
RUN curl -L https://gitea.com/gitea/gitea-mcp/releases/download/v0.2.0/gitea-mcp_Linux_x86_64.tar.gz \
|
||||
| tar -xz -C /usr/local/bin \
|
||||
&& chmod +x /usr/local/bin/gitea-mcp
|
||||
worker_custom_actions: |
|
||||
ENV GITEA_HOST="https://gitea.com"
|
||||
ENV GITEA_INSECURE="false"
|
||||
ENV GITEA_ACCESS_TOKEN="<your personal access token>"
|
||||
mcp_server_commands: ["gitea-mcp"]
|
||||
port: 8000
|
||||
env:
|
||||
GITEA_HOST: "https://code.alexpires.me"
|
||||
GITEA_ACCESS_TOKEN: "{{ lookup('env', 'GITEA_APP_TOKEN') }}"
|
||||
|
||||
tasks:
|
||||
- name: Setup Pods
|
||||
ansible.builtin.include_tasks:
|
||||
file: tasks/mcp-proxy.yml
|
||||
loop: "{{ mcp_servers }}"
|
||||
@@ -3,6 +3,7 @@
|
||||
vars:
|
||||
podman_user: "{{ ollama_user | default('ollama') }}"
|
||||
podman_group: "{{ ollama_group | default('ollama') }}"
|
||||
podman_extra_groups: "users"
|
||||
podman_user_home: "{{ ollama_home | default('/home/ollama') }}"
|
||||
podman_user_folders:
|
||||
- data
|
||||
|
||||
+18
-113
@@ -24,67 +24,9 @@
|
||||
- acl
|
||||
state: present
|
||||
|
||||
- name: Create group and user for workloads
|
||||
become: true
|
||||
ansible.builtin.group:
|
||||
name: "{{ podman_group }}"
|
||||
system: true
|
||||
|
||||
- name: Create user and group for containers
|
||||
become: true
|
||||
ansible.builtin.user:
|
||||
name: "{{ podman_user }}"
|
||||
groups: "{{ podman_group }}"
|
||||
shell: /bin/bash
|
||||
home: "{{ podman_user_home }}"
|
||||
group: "{{ podman_group }}"
|
||||
|
||||
- name: Disable password login for user
|
||||
ansible.builtin.command: passwd -d "{{ podman_user }}"
|
||||
become: true
|
||||
changed_when: false
|
||||
|
||||
- name: SELinux tasks (RedHat only)
|
||||
when: ansible_os_family == 'RedHat'
|
||||
become: true
|
||||
block:
|
||||
- name: Persistently set SELinux context for home directories on AI home
|
||||
community.general.sefcontext:
|
||||
target: "{{ podman_user_home }}(/.*)?"
|
||||
setype: user_home_dir_t
|
||||
state: present
|
||||
|
||||
- name: Apply SELinux context changes to AI home directories
|
||||
ansible.builtin.command: restorecon -Rv {{ podman_user_home }}
|
||||
changed_when: false
|
||||
|
||||
- name: Create user home
|
||||
become: true
|
||||
ansible.builtin.file:
|
||||
path: "{{ podman_user_home }}"
|
||||
state: directory
|
||||
owner: "{{ podman_user }}"
|
||||
group: "{{ podman_group }}"
|
||||
mode: "0750"
|
||||
|
||||
- name: Create build folders
|
||||
become: true
|
||||
ansible.builtin.file:
|
||||
path: "{{ podman_user_home }}/build"
|
||||
state: directory
|
||||
owner: "{{ podman_user }}"
|
||||
group: "{{ podman_group }}"
|
||||
mode: "0750"
|
||||
|
||||
- name: Create folders
|
||||
become: true
|
||||
ansible.builtin.file:
|
||||
path: "{{ podman_user_home }}/{{ item }}"
|
||||
state: directory
|
||||
owner: "{{ podman_user }}"
|
||||
group: "{{ podman_group }}"
|
||||
mode: "0750"
|
||||
loop: "{{ podman_user_folders }}"
|
||||
- name: Setup user
|
||||
ansible.builtin.include_tasks:
|
||||
file: podman/user.yml
|
||||
|
||||
- name: Enable sudo access to podman user (temporary)
|
||||
become: true
|
||||
@@ -118,53 +60,6 @@
|
||||
changed_when: false
|
||||
register: gid
|
||||
|
||||
- name: Ensure rootless Podman works with overlay driver on Debian-family systems
|
||||
when: ansible_os_family == 'Debian'
|
||||
become: true
|
||||
vars:
|
||||
subuid_range: "100000:65536"
|
||||
block:
|
||||
- name: Install required packages for rootless Podman overlay support
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- uidmap
|
||||
- fuse-overlayfs
|
||||
- libslirp0
|
||||
- slirp4netns
|
||||
state: present
|
||||
update_cache: true
|
||||
|
||||
- name: Ensure subuid entry exists for the user
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/subuid
|
||||
line: "{{ podman_user }}:{{ subuid_range }}"
|
||||
create: true
|
||||
state: present
|
||||
regexp: "^{{ podman_user }}:"
|
||||
mode: "0644"
|
||||
|
||||
- name: Ensure subgid entry exists for the user
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/subgid
|
||||
line: "{{ podman_user }}:{{ subuid_range }}"
|
||||
create: true
|
||||
state: present
|
||||
regexp: "^{{ podman_user }}:"
|
||||
mode: "0644"
|
||||
|
||||
- name: Ensure overlay module is loaded # noqa no-ignore-errors
|
||||
community.general.modprobe:
|
||||
name: overlay
|
||||
state: present
|
||||
|
||||
- name: Ensure overlay module loads on boot
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/modules
|
||||
line: overlay
|
||||
create: true
|
||||
state: present
|
||||
mode: "0644"
|
||||
|
||||
- name: Run tasks as podman user
|
||||
become: true
|
||||
become_user: "{{ podman_user }}"
|
||||
@@ -175,6 +70,16 @@
|
||||
name: "{{ podman_network_name }}"
|
||||
state: present
|
||||
|
||||
- name: Copy build files to user home
|
||||
ansible.builtin.copy:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ podman_user_home }}/build/"
|
||||
owner: "{{ podman_user }}"
|
||||
group: "{{ podman_group }}"
|
||||
mode: "0644"
|
||||
loop: "{{ podman_build_files | default([]) }}"
|
||||
when: podman_build_files is defined and podman_build_files | length > 0
|
||||
|
||||
- name: Build containers images
|
||||
containers.podman.podman_image:
|
||||
name: "{{ podman_user }}/{{ item.name }}"
|
||||
@@ -187,7 +92,7 @@
|
||||
tag: "latest"
|
||||
state: present
|
||||
loop: "{{ pods }}"
|
||||
when: item.build is defined
|
||||
when: item.build is defined and item.build.dockerfile is defined
|
||||
|
||||
- name: Pull the requested images
|
||||
containers.podman.podman_image:
|
||||
@@ -195,13 +100,13 @@
|
||||
tag: "{{ item.repo.tag | default('latest') }}"
|
||||
state: present
|
||||
loop: "{{ pods }}"
|
||||
when: item.repo is defined
|
||||
when: item.repo is defined and item.repo.image is defined
|
||||
|
||||
- name: Create pods
|
||||
containers.podman.podman_container:
|
||||
name: "{{ item.name }}"
|
||||
image: "{{ item.repo.image | default(podman_user + '/' + item.name) }}"
|
||||
state: started
|
||||
state: "{{ item.state | default('present') }}"
|
||||
device: "{{ item.device | default(omit) }}"
|
||||
env: "{{ item.env | default(omit) }}"
|
||||
network: "{{ podman_network_name | default(omit) }}"
|
||||
@@ -231,8 +136,8 @@
|
||||
become: true
|
||||
ansible.builtin.systemd:
|
||||
name: "podman-{{ item.name }}"
|
||||
enabled: true
|
||||
state: started
|
||||
enabled: "{{ item.systemd.enabled | default(true) }}"
|
||||
state: "{{ item.systemd.state | default('started') }}"
|
||||
loop: "{{ pods }}"
|
||||
|
||||
- name: Remove temporary sudo access
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
- name: Check if required vars are set
|
||||
ansible.builtin.fail:
|
||||
msg: "Required variables are not set for Podman setup. Please check your playbook variables.)"
|
||||
when:
|
||||
- podman_user is not defined
|
||||
- podman_group is not defined
|
||||
- podman_user_home is not defined
|
||||
|
||||
- name: Create group
|
||||
become: true
|
||||
ansible.builtin.group:
|
||||
name: "{{ podman_group }}"
|
||||
system: true
|
||||
|
||||
- name: Create user
|
||||
become: true
|
||||
ansible.builtin.user:
|
||||
name: "{{ podman_user }}"
|
||||
groups: "{{ podman_extra_groups | default([]) }}"
|
||||
shell: /bin/bash
|
||||
home: "{{ podman_user_home }}"
|
||||
group: "{{ podman_group }}"
|
||||
|
||||
- name: Disable password login for user
|
||||
ansible.builtin.command: passwd -d "{{ podman_user }}"
|
||||
become: true
|
||||
changed_when: false
|
||||
|
||||
- name: Create user home
|
||||
become: true
|
||||
ansible.builtin.file:
|
||||
path: "{{ podman_user_home }}"
|
||||
state: directory
|
||||
owner: "{{ podman_user }}"
|
||||
group: "{{ podman_group }}"
|
||||
mode: "0750"
|
||||
|
||||
- name: Create build folders
|
||||
become: true
|
||||
ansible.builtin.file:
|
||||
path: "{{ podman_user_home }}/build"
|
||||
state: directory
|
||||
owner: "{{ podman_user }}"
|
||||
group: "{{ podman_group }}"
|
||||
mode: "0750"
|
||||
|
||||
- name: Create folders
|
||||
become: true
|
||||
ansible.builtin.file:
|
||||
path: "{{ podman_user_home }}/{{ item }}"
|
||||
state: directory
|
||||
owner: "{{ podman_user }}"
|
||||
group: "{{ podman_group }}"
|
||||
mode: "0750"
|
||||
loop: "{{ podman_user_folders }}"
|
||||
|
||||
- name: "Add SSH Authorized key"
|
||||
become: true
|
||||
ansible.posix.authorized_key:
|
||||
user: "{{ podman_user }}"
|
||||
key: "{{ podman_user_pubkey }}"
|
||||
state: "{{ 'present' if podman_user_pubkey is defined else 'absent' }}"
|
||||
when: podman_user_pubkey is defined and podman_user_pubkey != ""
|
||||
|
||||
- name: SELinux tasks (RedHat only)
|
||||
when: ansible_os_family == 'RedHat'
|
||||
become: true
|
||||
block:
|
||||
- name: Persistently set SELinux context
|
||||
community.general.sefcontext:
|
||||
target: "{{ podman_user_home }}(/.*)?"
|
||||
setype: user_home_dir_t
|
||||
state: present
|
||||
|
||||
- name: Persistently set SELinux context (ssh authorized keys)
|
||||
community.general.sefcontext:
|
||||
target: "{{ podman_user_home }}/.ssh/authorized_keys"
|
||||
setype: ssh_home_t
|
||||
state: present
|
||||
when: podman_user_pubkey is defined and podman_user_pubkey != ""
|
||||
|
||||
- name: Apply SELinux context
|
||||
ansible.builtin.command: restorecon -Rv {{ podman_user_home }}
|
||||
changed_when: false
|
||||
Reference in New Issue
Block a user