diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index af1dd201..00000000 --- a/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -FROM golang - -COPY . /opt/gochan - -EXPOSE 80 - -ENV DBTYPE=postgresql -ENV GCVERSION=v2.9.1 -ENV FROMDOCKER=1 - -RUN /opt/gochan/vagrant/bootstrap.sh - - - -CMD [ "/opt/gochan/gochan" ] \ No newline at end of file diff --git a/Makefile b/Makefile index 008a46d7..942b6b28 100644 --- a/Makefile +++ b/Makefile @@ -67,7 +67,8 @@ install: cp ${DO_SYMLINKS} -f ./gochan ${PREFIX}/bin/${BINEXE} cp ${DO_SYMLINKS} -f ./*.sql ${PREFIX}/share/gochan/ cp ${DO_SYMLINKS} -rf ./templates ${PREFIX}/share/gochan/ - cd html && cp -rft ${DOCUMENT_ROOT} $(foreach file,${DOCUMENT_ROOT_FILES},${file}) +# cd html && cp -rft ${DOCUMENT_ROOT} $(foreach file,${DOCUMENT_ROOT_FILES},${file}) + cd html $(foreach file,${DOCUMENT_ROOT_FILES}, && cp -rf ${file} ${DOCUMENT_ROOT}) $(info gochan successfully installed. If you haven't already, you should run) $(info cp sample-configs/gochan.example.json /etc/gochan/gochan.json) ifeq (${GCOS_NAME},linux) diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index 3ac56a81..00000000 --- a/docker-compose.yml +++ /dev/null @@ -1,4 +0,0 @@ -version: '3' -services: - gochan: - build: . \ No newline at end of file diff --git a/docker/.gitignore b/docker/.gitignore new file mode 100644 index 00000000..1120be9a --- /dev/null +++ b/docker/.gitignore @@ -0,0 +1 @@ +docker-compose.yml diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 00000000..e0611823 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,57 @@ +FROM golang:1.13.9-alpine3.11 + +RUN apk --no-cache add \ + postgresql-client \ + mariadb-client \ + sqlite \ + nginx \ + ffmpeg \ + make \ + git \ + gcc \ + musl-dev \ + bash + +RUN mkdir -p /root/bin \ + && ln -s /usr/lib/go-1.13/bin/* /root/bin/ \ + && export PATH=$PATH:/root/bin \ + && echo "export PATH=$PATH:/root/bin" >> /root/.bashrc \ + && rm -f /etc/nginx/sites-enabled/* /etc/nginx/sites-available/* \ + && mkdir -p /var/lib/nginx \ + && mkdir -p /var/lib/nginx/tmp \ + && mkdir -p /run/nginx/ + +WORKDIR /opt/gochan + +# Get dependencies +COPY Makefile . +RUN make dependencies + +RUN rm /etc/nginx/conf.d/default.conf +COPY sample-configs/gochan-fastcgi.nginx /etc/nginx/conf.d/gochan.conf +COPY sample-configs/gochan.example.json /etc/gochan/gochan.json + +# Get all +COPY . . + +EXPOSE 9000 + +CMD ls -la /opt/gochan && ls -la && ls -la .. && sed -i /etc/gochan/gochan.json \ + -e 's/"Port": 8080/"Port": 9000/' \ + -e 's/"UseFastCGI": false/"UseFastCGI": true/' \ + -e 's/"DomainRegex": ".*"/"DomainRegex": "(https|http):\\\/\\\/(.*)\\\/(.*)"/' \ + -e 's#"DocumentRoot": "html"#"DocumentRoot": "/srv/gochan"#' \ + -e 's#"TemplateDir": "templates"#"TemplateDir": "/usr/local/share/gochan/templates"#' \ + -e 's#"LogDir": "log"#"LogDir": "/var/log/gochan"#' \ + -e 's/"Verbosity": 0/"Verbosity": 1/' \ + -e "s/\"DBtype\".*/\"DBtype\": \"${DBTYPE}\",/" \ + -e "s/\"DBhost\".*/\"DBhost\": \"tcp(${DATABASE_HOST}:${DATABASE_PORT})\",/" \ + -e "s/\"DBname\".*/\"DBname\": \"${DATABASE_NAME}\",/" \ + -e "s/\"DBusername\".*/\"DBusername\": \"${DATABASE_USER}\",/" \ + -e "s/\"DBpassword\".*/\"DBpassword\": \"${DATABASE_PASSWORD}\",/" \ + && make \ + && make install \ + && nginx \ + && echo "pinging db" \ + && docker/wait-for.sh $DATABASE_HOST:$DATABASE_PORT -t 30 \ + && /opt/gochan/gochan diff --git a/docker/README.md b/docker/README.md new file mode 100644 index 00000000..ad405127 --- /dev/null +++ b/docker/README.md @@ -0,0 +1,15 @@ +To run docker you have several choices. + +If you want the docker container to use the host's database, copy `docker-compose.yml.default` to `docker-compose.yml` and edit the new file with your host's information. + +If you want docker to manage the databse, use `docker-compose-[database].yml`. + +If you are using MacOS and need better file sync between the host and the container, use `docker-compose-syncForMac.yml`. + +To use, run `docker-compose -f [docker-compose.yml file you chose] up --build`. To stop, simply use control+c to send a stop signal. This stops the docker containers but it does not delete them. They are merely frozen. + +To delete the containers run `docker-compose -f [file you chose] down`. If you have a container that has a database (for example, if you chose `docker-compose-mariadb.yml`), this command will delete the database too. + +If you want to use a specific docker-compose file as the default for your own computer, or you want to edit one of the default configurations given here (to change the database type, for example), copy the file and name it `docker-compose.yml`. This way, you can omit specifying the file when using docker-compose. For example, `docker-compose down` is the same as `docker-compose -f docker-compose.yml down`. The file is added to .gitignore so that your local config won't be accidentally commited. + +Docker caches builds. When files change, it has to rebuild from whenever that file was added to the docker image. For example, the docker file adds `Makefile` at first and ignores the rest of the files. It uses it to download the dependencies, which can take a while. After that, it adds the rest of the files. This means that if a file is changed in a source file, docker won't have to rebuild. But if the Makefile changes, it will be forced to rebuild. This can cause Docker to bloat up after a while. Periodically remember to run `docker image prune` (also search for other deletion commands) to keep docker's storage usage relatively low. All images used thus far use Alpine, which is a small OS compared to Ubuntu or other much larger builds. diff --git a/docker/SyncForMac b/docker/SyncForMac new file mode 100644 index 00000000..3584e865 --- /dev/null +++ b/docker/SyncForMac @@ -0,0 +1,4 @@ +FROM alpine:3.9 +RUN apk --no-cache add rsync lsyncd +# Declared in docker-compose +#CMD lsyncd -delay 1 -nodaemon -rsync /source /cache \ No newline at end of file diff --git a/docker/alpineMysql/Dockerfile b/docker/alpineMysql/Dockerfile new file mode 100644 index 00000000..a8e7ab99 --- /dev/null +++ b/docker/alpineMysql/Dockerfile @@ -0,0 +1,11 @@ +FROM alpine:3.9 + +WORKDIR /app +RUN apk --update add mysql && rm -f /var/cache/apk/* + +COPY startup.sh /startup.sh +COPY my.cnf /etc/mysql/my.cnf + +EXPOSE 3306 +CMD ["/startup.sh"] + diff --git a/docker/alpineMysql/my.cnf b/docker/alpineMysql/my.cnf new file mode 100644 index 00000000..0a60e5e9 --- /dev/null +++ b/docker/alpineMysql/my.cnf @@ -0,0 +1,10 @@ +[mysqld] +user = root +datadir = /app/mysql +port = 3306 +log-bin = /app/mysql/mysql-bin +bind-address = 0.0.0.0 +max_allowed_packet=256M + +# Disabling symbolic-links is recommended to prevent assorted security risks +symbolic-links=0 \ No newline at end of file diff --git a/docker/alpineMysql/startup.sh b/docker/alpineMysql/startup.sh new file mode 100755 index 00000000..8837cd66 --- /dev/null +++ b/docker/alpineMysql/startup.sh @@ -0,0 +1,62 @@ +#!/bin/sh + +if [ -d /app/mysql ]; then + echo "[i] MySQL directory already present, skipping creation" +else + echo "[i] MySQL data directory not found, creating initial DBs" + + mysql_install_db --user=root > /dev/null + + if [ "$MYSQL_ROOT_PASSWORD" = "" ]; then + echo "No password given" + exit 1; + fi + + MYSQL_DATABASE=${MYSQL_DATABASE:-""} + MYSQL_USER=${MYSQL_USER:-""} + MYSQL_PASSWORD=${MYSQL_PASSWORD:-""} + + if [ ! -d "/run/mysqld" ]; then + mkdir -p /run/mysqld + fi + + tfile=`mktemp` + if [ ! -f "$tfile" ]; then + return 1 + fi + + cat << EOF > $tfile +USE mysql; +FLUSH PRIVILEGES ; +GRANT ALL ON *.* TO 'root'@'localhost' identified by '$MYSQL_ROOT_PASSWORD' WITH GRANT OPTION ; +GRANT ALL ON *.* TO 'root'@'%' identified by '$MYSQL_ROOT_PASSWORD' WITH GRANT OPTION ; +SET PASSWORD FOR 'root'@'localhost'=PASSWORD('${MYSQL_ROOT_PASSWORD}') ; +DROP DATABASE IF EXISTS test ; +FLUSH PRIVILEGES ; +EOF + + # Create new database + if [ "$MYSQL_DATABASE" != "" ] && [ "$MYSQL_USER" != "" ] && [ "$MYSQL_PASSWORD" != "" ]; then + echo "[i] Creating database: $MYSQL_DATABASE" + echo "CREATE DATABASE IF NOT EXISTS \`$MYSQL_DATABASE\` CHARACTER SET utf8 COLLATE utf8_general_ci;" >> $tfile + + # set new User and Password + echo "[i] Creating user: $MYSQL_USER" + echo "CREATE USER '$MYSQL_USER'@'%' IDENTIFIED BY '$MYSQL_PASSWORD';" >> $tfile + echo 'FLUSH PRIVILEGES;' >> $tfile + echo "GRANT ALL ON \`$MYSQL_DATABASE\`.* to '$MYSQL_USER'@'%';" >> $tfile + else + echo "User, database, or password is empty." + exit 1; + fi + + echo 'FLUSH PRIVILEGES;' >> $tfile + echo "[i] run tempfile: $tfile" + + /usr/bin/mysqld --user=root --bootstrap < $tfile + # rm -f $tfile +fi + + +exec /usr/bin/mysqld --user=root --console --debug=d,general,query --skip-networking=0 --default-authentication-plugin=mysql_native_password + diff --git a/docker/docker-compose-mariadb.yaml b/docker/docker-compose-mariadb.yaml new file mode 100644 index 00000000..d8af8830 --- /dev/null +++ b/docker/docker-compose-mariadb.yaml @@ -0,0 +1,29 @@ +version: '3.2' +services: + gochan: + build: + context: .. + dockerfile: docker/Dockerfile + ports: + - "80" + volumes: + - ../:/opt/gochan # note: this doesn't work too well in MacOS. + environment: + - DBTYPE=mysql + - DATABASE_HOST=mysql + - DATABASE_PORT=3306 + - DATABASE_NAME=gochan + - DATABASE_USER=gochan + - DATABASE_PASSWORD=gochan + depends_on: + - mysql + + mysql: + expose: + - "3306" + build: ./alpineMysql + environment: + - MYSQL_ROOT_PASSWORD=root + - MYSQL_DATABASE=gochan + - MYSQL_USER=gochan + - MYSQL_PASSWORD=gochan diff --git a/docker/docker-compose-syncForMac.yml b/docker/docker-compose-syncForMac.yml new file mode 100644 index 00000000..dd04cbb0 --- /dev/null +++ b/docker/docker-compose-syncForMac.yml @@ -0,0 +1,37 @@ +# Reading host files from a docker container on MacOS is really slow. This is set up as a workaround. +version: '3.2' +services: + gochan: + build: + context: .. + dockerfile: docker/Dockerfile + ports: + - "80" + environment: + - DBTYPE=mysql # change this to 'postgresql' if needed + - DATABASE_HOST=host.docker.internal + - DATABASE_PORT=3306 + - DATABASE_NAME=gochan + - DATABASE_USER=root + - DATABASE_PASSWORD=root + volumes: + - type: volume + source: api_volume + target: /opt/gochan + consistency: cached + sync: + build: + context: .. + dockerfile: SyncForMac + volumes: + - type: bind + source: ../ + target: /source + consistency: cached + - type: volume + source: api_volume + target: /cache + consistency: cached + command: "lsyncd -delay 1 -nodaemon -rsync /source /cache" +volumes: + api_volume: \ No newline at end of file diff --git a/docker/docker-compose.yml.default b/docker/docker-compose.yml.default new file mode 100644 index 00000000..b6aecfac --- /dev/null +++ b/docker/docker-compose.yml.default @@ -0,0 +1,17 @@ +version: '3.2' +services: + gochan: + build: + context: .. + dockerfile: docker/Dockerfile + ports: + - "80" + volumes: + - ../:/opt/gochan # note: this doesn't work too well in MacOS. + environment: + - DBTYPE=mysql # change this to 'postgresql' if needed + - DATABASE_HOST=host.docker.internal + - DATABASE_PORT=3306 + - DATABASE_NAME=gochan + - DATABASE_USER=root + - DATABASE_PASSWORD=root diff --git a/docker/wait-for.sh b/docker/wait-for.sh new file mode 100755 index 00000000..567226fc --- /dev/null +++ b/docker/wait-for.sh @@ -0,0 +1,80 @@ +#!/bin/sh + +TIMEOUT=15 +QUIET=0 + +echoerr() { + if [ "$QUIET" -ne 1 ]; then printf "%s\n" "$*" 1>&2; fi +} + +usage() { + exitcode="$1" + cat << USAGE >&2 +Usage: + $cmdname host:port [-t timeout] [-- command args] + -q | --quiet Do not output any status messages + -t TIMEOUT | --timeout=timeout Timeout in seconds, zero for no timeout + -- COMMAND ARGS Execute command with args after the test finishes +USAGE + exit "$exitcode" +} + +wait_for() { + for i in `seq $TIMEOUT` ; do + nc -z "$HOST" "$PORT" > /dev/null 2>&1 + + result=$? + if [ $result -eq 0 ] ; then + if [ $# -gt 0 ] ; then + exec "$@" + fi + exit 0 + fi + sleep 1 + done + echo "Operation timed out" >&2 + exit 1 +} + +while [ $# -gt 0 ] +do + case "$1" in + *:* ) + HOST=$(printf "%s\n" "$1"| cut -d : -f 1) + PORT=$(printf "%s\n" "$1"| cut -d : -f 2) + shift 1 + ;; + -q | --quiet) + QUIET=1 + shift 1 + ;; + -t) + TIMEOUT="$2" + if [ "$TIMEOUT" = "" ]; then break; fi + shift 2 + ;; + --timeout=*) + TIMEOUT="${1#*=}" + shift 1 + ;; + --) + shift + break + ;; + --help) + usage 0 + ;; + *) + echoerr "Unknown argument: $1" + usage 1 + ;; + esac +done + +if [ "$HOST" = "" -o "$PORT" = "" ]; then + echoerr "Error: you need to provide a host and port to test." + usage 2 +fi + +wait_for "$@" +