Skip to content
View in the app

A better way to browse. Learn more.

Unraid

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

Python/Flask Web App & Docker Container Permissions

Featured Replies

Hi Guys,

 

I am currently learning Python and have started to learn Flask (Web Framework).  I have created a simple Web App and since I have unRAID I thought I would try to get it running in a Docker Container.  I played around and got it running with a few base images such as ubuntu:18.04 & python:3-alpine without persisting any data.

 

So I have decided to try and tackle the task of persisting data.  I am using a SQLite database via SqlAlchemy (ORM) & the app saves user uploaded images.  I have been able to get it all working with the exception of permissions (The directories/files created are still owned by root).  I decided to try using linuxserver's Ubuntu base image thinking that might solve my issue but no luck so far.

Here is what I have:

 

Dockerfile

#LinuxServers base Ubuntu image
FROM lsiobase/ubuntu:bionic

#Update & Install Python, PIP & Virtual Environments
RUN apt-get update && apt-get install \
    -y python3 python3-pip python3-venv

#Set Work Directory
WORKDIR /app

#Copy the App
COPY . /app

#Create Virtual Environment
RUN python3 -m venv /app/venv

#Activate Virtual Environment and install dependencies
RUN . /app/venv/bin/activate && pip install -r requirements.txt

#Expose Flask Port
EXPOSE 5000

#Directory to store App's DB & Images
VOLUME /config

#Run the App
CMD . /app/venv/bin/activate && exec python run.py

(I know I don't need to run the App in a Virtual Environment but was I doing it to learn how Python venv works)

 

run.py (The python file that creates the DB + Image folder in /Config and starts the App)

import os
import shutil
from mywebapp import app
from mywebapp import db

#Create the database if it does not exist
def createdb():
    if not os.path.exists('/config/site.db'):
        db.create_all()
        
#Create the images directory if it does not exist and copy the default image
def createimgagefolder():
    if not os.path.exists('/config/images'):
        os.mkdir('/config/images')
    if not os.path.exists('/config/images/default.png'):
        project_root = os.path.abspath(os.path.dirname(__file__))
        defaultimgpath = os.path.join(project_root, 'myapp', 'static', 'img', 'default.png')
        shutil.copyfile(defaultimgpath, '/config/images/default.png')
        
if __name__ == '__main__':
    createdb()
    createimgagefolder()
    #host must be 0.0.0.0 to be accessed from outside the containter
    app.run(host='0.0.0.0')

 

__init__.py (I included this as this defines the location of the database: /config/site.db)

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)

#Location of database
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////config/site.db'

db = SQLAlchemy(app)

#Import blueprints & register them
from myapp.settings.routes import appsettings
from myapp.posts.routes import posts
from myapp.main.routes import main
app.register_blueprint(appsettings)
app.register_blueprint(posts)
app.register_blueprint(main)

docker run command

run -d --name='myapp' --net='bridge' --cpuset-cpus='1,3,5,7,9,11' -e TZ="America/Denver" -e HOST_OS="Unraid" -e 'PUID'='99' -e
'PGID'='100' -p '5000:5000/tcp' -v '/mnt/user/appdata/myapp':'/config':'rw' 'mydockerhubacct/myapp'

So as I stated above the creation of db, image folder and copying of the default.png works but they are all owned by root.  My understanding is that docker runs all of its containers under the root user domain.  So i tried adding USER 99:100 to the docker file thinking that if the app was run as 99:100 then it would create the db and image folder as 99:100 but I get a mkdir permission error.

 

I also tried changing the ownership after creation in run.py

#Create the database if it does not exist
def createdb():
    if not os.path.exists('/config/site.db'):
        db.create_all()
	os.chown('/config/site.db', uid=99, gid=100)

This works but doesn't seem like a great solution as I would also need to code it in my function that saves the images users upload.

I have spent hours trying to figure out how others are doing this (such as LinuxServers Radarr, Sonarr etc) by reading their Dockerfiles and following it back to the Github repositories but it's got me stumped.

Any help would be immensely appreciated! I am learning python, Flask, Docker etc. on my own and don't really have a teacher or mentor to ask any questions.

 

I also want to thank Limetech for unRaid because that's what got me down the path of learning to code and experiment with Docker, and so far I am really enjoying it.

Thanks guys!

  • Author

I am not scared of learning, even a link to some documentation would be helpful.  Persisting data when using docker seems to be very common, there must be a common practice that is followed?  How is everyone else setting the owner of their /config data?

I believe that many Docker images use a startup script to change the permissions of the config folder and all its files. Such scripts i believe use the PUID and PGID environmental variables (or equivalent), which can be set via docker to match the host. Additionally rather than setting the USER in the docker file many use scripts to create the user/group (from the environmental variables) and then start their app as that user at runtime. 

This script from jlesage's handbrake container is an example. 

https://github.com/jlesage/docker-handbrake/blob/master/rootfs/etc/cont-init.d/handbrake.sh 

 

I think the LinuxServer images do something similar, but they use a whole init system in their containers (s6 i want to say) and the particular init scripts that deal with users are buried in their base images i think.

 

Edited by primeval_god

Archived

This topic is now archived and is closed to further replies.

Account

Navigation

Search

Search

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.