Closed brettwilcox closed 3 years ago
Couldn’t you use flairs/tags?
Another note, the reason I do not want a monorepo is that I would like to keep issue tracking separate since it makes it easier to manage
100% okay with this. I would still not use submodules and just use this as the build repository for docker and documentation. The docker-compose.yml will pull the images from docker hub and those images are triggered from each repository using GitHub Actions.
I'm just trying to convey that you will 100% have issues with submodules no matter how perfectly maintained they are. It's just near impossible since users are not very familiar with them as they are not used very often.
Another note, the reason I do not want a monorepo is that I would like to keep issue tracking separate since it makes it easier to manage
100% okay with this. I would still not use submodules and just use this as the build repository for docker and documentation. The docker-compose.yml will pull the images from docker hub and those images are triggered from each repository using GitHub Actions.
I'm just trying to convey that you will 100% have issues with submodules no matter how perfectly maintained they are. It's just near impossible since users are not very familiar with them as they are not used very often.
Understood and will stay away from them!
Couldn’t you use flairs/tags?
Absolutely but I dont think this is what I want for this project
@brettwilcox Okay so here is an issue. Right now you need to edit a dockerfile for the react website in order to make sure your websocket url is correct. How would I remedy this with a premade image? Is there a way I can use a flag or env var?
Below is an example pattern I use.
IMAGE=myimage
TAG=1.2.3
services:
my-app:
env_file:
- ".env"
labels:
- "IMAGE=${IMAGE}"
- "TAG=${TAG}"
build:
context: ./docker/my-app
args:
- "IMAGE=${IMAGE}"
- "TAG=${TAG}"
restart: always
ARG IMAGE=${IMAGE}
ARG TAG=${TAG}
# Image and version to pull
FROM ${IMAGE}:${TAG}
I've slept since I did this...
You would have a .env.example file in the root with the documented environment variables.
How would I remedy this with a premade image? Is there a way I can use a flag or env var?
IIRC ARG in dockerfiles is used for build-time variables - if we want to pre-build a docker image, and have websocket URL as a run-time variable, we'd want ENV, so the Dockerfile would include stuff like:
ENV WS_URL=localhost
CMD sed -i "s|stream.gud.software|$WS_URL|g" public/config.json && serve -s build -l 80
(Then you can override WS_URL using whatever mechanism (docker-compose.yml
, .env
, docker -e
, ...) and it'll be inserted into the config file at runtime)
I've made a few PRs to each of the repos. Right now, in hopes that this is useful information, I have everything running from these commands and this docker-compose.yml file:
(to build the docker images locally)
mkdir lightspeed
cd lightspeed
git clone https://github.com/GRVYDEV/Lightspeed-ingest/
cd Lightspeed-ingest
docker build . -t lightspeed-ingest-test
cd ..
git clone https://github.com/GRVYDEV/Lightspeed-webrtc/
cd Lightspeed-webrtc
docker build . -t lightspeed-webrtc-test
cd ..
git clone https://github.com/GRVYDEV/Lightspeed-react/
cd Lightspeed-react
sed -i "s|stream.gud.software:8080|<my public domain>:8085|g" src/wsUrl.js
docker build . -t lightspeed-react-test
cd ..
(docker-compose.yml)
version: '3.7'
services:
lightspeed_ingest:
image: lightspeed-ingest-test
container_name: lightspeed_ingest
restart: unless-stopped
ports:
- 8084:8084
lightspeed_webrtc:
image: lightspeed-webrtc-test
container_name: lightspeed_webrtc
restart: unless-stopped
entrypoint: lightspeed-webrtc
command: --addr=0.0.0.0 --ip=<my public IP> --ports=19050-19100
ports:
- 8085:8080 # WebRTC
- 65535:65535/udp # RTP
- 19050-19100:19050-19100 # WebRTC PeerConnection
- 19050-19100:19050-19100/udp # WebRTC PeerConnection UDP
lightspeed_react:
image: lightspeed-react-test
container_name: lightspeed_react
restart: unless-stopped
ports:
- 8086:80
Now from this setup, I have the react web server running on port 8086, the websocket server on port 8085, and the FTL port on 8084. I also have port 65535 forwarded for RTP and ports 19050-19100 forwarded for WebRTC ICE connections.
Once these images exist on docker hub, I'm sure this setup will become much simpler.
Hope that's helpful!
I've made a few PRs to each of the repos. Right now, in hopes that this is useful information, I have everything running from these commands and this docker-compose.yml file:
(to build the docker images locally)
mkdir lightspeed cd lightspeed git clone https://github.com/GRVYDEV/Lightspeed-ingest/ cd Lightspeed-ingest docker build . -t lightspeed-ingest-test cd .. git clone https://github.com/GRVYDEV/Lightspeed-webrtc/ cd Lightspeed-webrtc docker build . -t lightspeed-webrtc-test cd .. git clone https://github.com/GRVYDEV/Lightspeed-react/ cd Lightspeed-react sed -i "s|stream.gud.software:8080|<my public domain>:8085|g" src/wsUrl.js docker build . -t lightspeed-react-test cd ..
(docker-compose.yml)
version: '3.7' services: lightspeed_ingest: image: lightspeed-ingest-test container_name: lightspeed_ingest restart: unless-stopped ports: - 8084:8084 lightspeed_webrtc: image: lightspeed-webrtc-test container_name: lightspeed_webrtc restart: unless-stopped entrypoint: lightspeed-webrtc command: --addr=0.0.0.0 --ip=<my public IP> --ports=19050-19100 ports: - 8085:8080 # WebRTC - 65535:65535/udp # RTP - 19050-19100:19050-19100 # WebRTC PeerConnection - 19050-19100:19050-19100/udp # WebRTC PeerConnection UDP lightspeed_react: image: lightspeed-react-test container_name: lightspeed_react restart: unless-stopped ports: - 8086:80
Now from this setup, I have the react web server running on port 8086, the websocket server on port 8085, and the FTL port on 8084. I also have port 65535 forwarded for RTP and ports 19050-19100 forwarded for WebRTC ICE connections.
Once these images exist on docker hub, I'm sure this setup will become much simpler.
Hope that's helpful!
Awesome work! Thank you so much! I am going to work on getting the images on docker hub ASAP along with github actions for building them
@k3d3 @brettwilcox Is there a way I could setup a stage in docker-compose file that would tell the lightspeed-react image to run the sed -i
command with a provided value? What I mean is if the main repo contained a docker compose and a .env file is there a way someone could edit the .env file and then the compose file would edit the proper values in each image? Im trying to figure out a solution that is basically clone the main repo, change a couple lines in a .env file and boom itll work
You could technically put a variable in an entrypoint: sed ${VARIABLE} && /entrypoint
or command:
block, which could be read from a .env file.
As a side note, I wrote reactserv which reads static react files from disk, and serves them from memory as well as modify them to set the root url in the react code. You could use a similar approach to serve your react code as well as replace values at start through an env variable. That way you can even have the final image based on scratch
(no OS) as long as you use go/rust and compile statically.
You could technically put a variable in an
entrypoint: sed ${VARIABLE} && /entrypoint
orcommand:
block, which could be read from a .env file.As a side note, I wrote reactserv which reads static react files from disk, and serves them from memory as well as modify them to set the root url in the react code. You could use a similar approach to serve your react code as well as replace values at start through an env variable. That way you can even have the final image based on
scratch
(no OS) as long as you use go/rust and compile statically.
So theoretically in the docker compose file I could do command: sed -i "s|stream.gud.software|ENV_VAR|g" build/config.json && serve -s build -l 80
which would replace this command
A simple solution to overriding the websocket url in a running container is to just document how to provide your own config.json
file using docker mounts.
While I'm not sure of the best solution, I would also like some way to change the port number as well, since I'm using port 8085 in my setup.
I do like that idea too - providing a config.json via docker volume - but that also seems pretty heavyweight for just a url change.
While I'm not sure of the best solution, I would also like some way to change the port number as well, since I'm using port 8085 in my setup.
Yup the plan is to have the config change the entire url including port. It sounds like we may mount a custom config and then point react at that
While I'm not sure of the best solution, I would also like some way to change the port number as well, since I'm using port 8085 in my setup.
Yup the plan is to have the config change the entire url including port. It sounds like we may mount a custom config and then point react at that
also I will add support for changing the websocket host URL as well in Lightspeed-webrtc once I get this docker stuff finished
I do like that idea too - providing a config.json via docker volume - but that also seems pretty heavyweight for just a url change.
I think it's a fairly common pattern - mounting config files into docker containers. While it's just a url/port change now it also allows further config easily later :)
I do like that idea too - providing a config.json via docker volume - but that also seems pretty heavyweight for just a url change.
It's probably not a bad idea to have a config file for this project in general. There does seem to be enough state to require some way of configuring the project (other than using sed
) and a single config (volumed read-only into each container) would solve this problem.
Alternatively, as someone mentioned above ENV variables are not a bad idea either. There are a lot of containers which use this.
This is fairly common, for example the official NGINX
image uses:
environment:
- NGINX_HOST=foobar.com
- NGINX_PORT=80
although I think this might actually just be a feature of NGINX
and not something handles by docker...
If having configuration within the code isn't desired, the entrypoint
of each container is also a good place to handle this (obviously, as long as these are runtime configurations. I haven't dug deep enough to see if this is the case).
I do like that idea too - providing a config.json via docker volume - but that also seems pretty heavyweight for just a url change.
I think it's a fairly common pattern - mounting config files into docker containers. While it's just a url/port change now it also allows further config easily later :)
Specifically in regards to the react site I know for SURE there will be more config in the future. Especially in respect to monetization when we get to that point (think stripe api key etc). In order to keep this project as general purpose as possible I want to make sure we make smart configuration decisions. Ideally 1 file for the whole project would be GREAT however I am very new to dockerization so I am all ears.
Both "one config.json for the project, mounted into each container" and "config stored in .env, which docker-compose passes into the containers via environment variables" sound good to me (though the first gives you all the JSON data types and structure, while the later only does key/value string pairs, so maybe the first is significantly better...?)
(I'm another person hoping for configurable port numbers as I'm already using 8084 :P)
@GRVYDEV okay, so I think this actually just goes deeper in general.
In the short term it likely makes sense to just choose something. Mentioned above:
entrypoint: sed ${VARIABLE} && /entrypoint
This will work and is very easy to configure. It allows you to pass in the variables via an .env
file and also set them by passing them in when running docker-compose
here are some references:
essentially, these variables end up being used as "build-args" which can modify the the container during build time.
Now, let's ignore docker
for a second because it can basically be thought of as any deployment environment.
So, for your future config needs, I would ignore docker
and focus on doing what is right for the project elements. A config file is probably the best idea. But really, spend some time thinking about an extensible method that fits your needs.
Hmm, after thinking about it, I definitely agree that a mounted config file is the way to go. Especially with docker-compose, those are very simple to make.
Within docker-compose.yml, you'd just add another section under lightspeed_react
:
volumes:
- ./local/path/to/config.json:/internal/path/to/config.json:ro
The ro
keeps it read-only within the container, and can be omitted to make it read-write (though we probably don't want that here).
@GRVYDEV there are some things you'll probably want to keep as docker configurable.
For example, the port mappings probably make the most sense being configured (via ENV or .env
file) and then keeping the project with default port values.
if this is unclear, basically, in the docker-compose.yml
you would change the port number before the :
to be:
lightspeed-ingest:
restart: on-failure
build: ingest/
network_mode: host
ports:
- "${LIGHTSPEED_PORT}:8084"
oh, additionally, you can also modify the CMD
for a container in the docker-compose.yml
so, for the WebRTC container, you could do:
lightspeed-webrtc:
restart: on-failure
build: webrtc/
network_mode: host
ports:
- "8080:8080"
- "65535:65535/udp"
command: ["lightspeed-webrtc", "--addr=${IP_ADDRESS}"]
Hmmmmm, looking deeper, looks like everything could be setup as a runtime variable configured in docker-compose
. The only thing standing out is: wsUrl.js
but this file could have an expression which checks for an ENV, and if that isn't set, sets to default
Hmmmmm, looking deeper, looks like everything could be setup as a runtime variable configured in
docker-compose
. The only thing standing out is:wsUrl.js
but this file could have an expression which checks for an ENV, and if that isn't set, sets to default
wsURL.js is no longer used. Instead there is a config.json file in the build folder
How about a shell entrypoint. Just make it sed things from env variables and make it call serve...
at the end. That solves a lot of it I think and is extensible.
Ideally a statically compiled program to do the shell script role AND the HTTP serving (that is, unless you do server side rendering) would be best. But you can do that later.
How about a shell entrypoint. Just make it sed things from env variables and make it call
serve...
at the end. That solves a lot of it I think and is extensible.Ideally a statically compiled program to do the shell script role AND the HTTP serving (that is, unless you do server side rendering) would be best. But you can do that later.
ENTRYPOINT
would likely be the best place for this script to run from.
Checkout the NGINX entrypoint.
The exec "$@"
at the end is particularly useful because it allows the CMD
to be run after the entrypoint script has finished.
How about a shell entrypoint. Just make it sed things from env variables and make it call
serve...
at the end. That solves a lot of it I think and is extensible.Ideally a statically compiled program to do the shell script role AND the HTTP serving (that is, unless you do server side rendering) would be best. But you can do that later.
While that is a quick fix we will be dealing with a lot of configuration values in the future so I want to be future oriented with this decision
ENTRYPOINT would likely be the best place for this script to run from.
Yes plus you could convert environment variables to flags to serve as well for convenience.
While that is a quick fix we will be dealing with a lot of configuration values in the future so I want to be future oriented with this decision
A shell entrypoint is quick to do but would be the best way I'd say, wether it's common practice or for ease of use for end users. The entrypoint can always be changed later to something more robust like rust or go without breaking changes.
I'll try to make a PR with a /bin/sh
script for Alpine (who needs bash right)
I opened https://github.com/GRVYDEV/Lightspeed-react/pull/10 with such entrypoint and a few tiny Dockerfile improvements. There is still a few questions to iron out and documentation to add though. Anyone, feel free to criticize 😉
I opened GRVYDEV/Lightspeed-react#10 with such entrypoint and a few tiny Dockerfile improvements. There is still a few questions to iron out and documentation to add though. Anyone, feel free to criticize wink
I am a Docker noob so I may be missing the point of the entrypoint script but this looks like I should be able to pass it a WEBSOCKET_HOST
env var and that will automatically replace it?
You need to replace the value at runtime, not build time. That way the user doesn't have to build the image himself. To replace it you need a server side entrypoint of some sort, like a shell script. Although for now there is no HTTP server in the image, I think it should be part of the image and entrypoint.
After having prepared Docker images we should also think of a K8S HELM package for Kubernetes (K8S).
For the config file, can we consider TOML? It's so much easier to read and work with.
For the config file, can we consider TOML
Agreed, but the configuration is in JSON for the React project (native format). And I'd think environment variables are easier to use than a configuration file at least for Docker (except for secrets where we should use files).
Closed with #34
Docker + Docker Compose
The project deployment needs to be simplified with a docker and docker-compose structure. We need a pull request to address adding this as a first class support model.