Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✅ Docker support #41

Merged
merged 9 commits into from
Dec 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.build/
.swiftpm/
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@ db.sqlite
Public
Resources
./feather
docker/datadir
ssh
108 changes: 108 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
FROM swift:5.3.1-focal as builder
WORKDIR /opt/feather

COPY . .

## Install required dependencies for the build
RUN apt-get update && apt-get install libxml2-dev libsqlite3-dev -y

## Allow the usage of private repository
### This part is for advanced user, ignore it if you don't use private repository in Swift package manager
## 1. Add SSH Hostname to known_host (This is use for Private repo in SPM)
## Here we add github.com hostname as when building the docker file we don't have an interactive shell
## It means it will be known from git, so won't request confirmation of the key
## You may want to add your own
## 2. It will use you private keys to clone private repository
## You private keys should be stored (Password less, decrypted) in the folder `ssh`
## for Continous integration, you will need a step to copy the decrypted key to the folder. Symbolic link won't work
RUN if [ -d "ssh" ]; then \
mkdir -p ~/.ssh/; \
eval `ssh-agent`; \
ssh-keyscan -H github.com >> ~/.ssh/known_hosts; \
fi

## Build the application
RUN echo "---> Build application"; \
if [ -d "ssh" ]; then \
eval `ssh-agent`; \
chmod 400 ssh/*; \
ssh-add ssh/*; \
swift build -c release --enable-test-discovery; \
else \
swift build -c release --enable-test-discovery; \
fi

RUN rm -rf */**/.DS_Store

## Organizing things up
RUN mkdir -p /tmp/app

## Check if the folder contains preexising DB/Folders.
## It means the user may have prepare Feather-CMS locally, in that case we will copy its content to the template folder
## So the user will keep what he prepared
RUN cd /opt/feather; if [ -f "db.sqlite" ]; then cp -pr db.sqlite /tmp/app; fi
RUN cd /opt/feather; if [ -d "Public" ]; then cp -pr Public /tmp/app; fi
RUN cd /opt/feather; if [ -d "Resources" ]; then cp -pr Resources /tmp/app; fi

## Prepare entry point
RUN \
echo '#!/bin/bash' > /tmp/app/start &&\
echo "[[ ! -d \"\${BASE_PATH}/db.sqlite\" && -d /opt/feather/db.sqlite ]] && cp -pr /opt/feather/db.sqlite \${BASE_PATH}/" >> /tmp/app/start &&\
echo "[[ ! -d \"\${BASE_PATH}/Public\" && -d /opt/feather/Public ]] && cp -pr /opt/feather/Public \${BASE_PATH}/" >> /tmp/app/start &&\
echo "[[ ! -d \"\${BASE_PATH}/Resources\" && -d /opt/feather/Resources ]] && cp -pr /opt/feather/Resources \${BASE_PATH}/" >> /tmp/app/start &&\
echo "Feather serve --hostname 0.0.0.0 --port \${BASE_PORT}" >> /tmp/app/start
RUN chmod 550 /tmp/app/start

## Keep only executables & resources (will be available in /opt/feather/bin )
RUN mv /opt/feather/.build/x86_64-unknown-linux-gnu/release /tmp/app/bin

## Copy any custom scripts under the `customscripts` folder
## If the user decide to use a diffent enty point from start, he can create hsi own scripts.
## Ex. We could imagine, starting 10 servers in one docker. The script would set, different folders, env variables. It will not work with embeded DB here...
## docker run -d -p 8080-8090:8080-8090 feather start_10_apps
RUN if [ -d "/opt/feather/customscripts" ]; then \
chmod 550 /opt/feather/customscripts/*; \
cp -pr /opt/feather/customscripts/* /tmp/app/; \
fi

## Clean up & keep only executbale from the build
RUN cd /; rm -rf /opt/feather; mv /tmp/app /opt/feather

## User feather
RUN groupadd -r feather && useradd --no-log-init -r -g feather feather
RUN chown -R feather:feather /opt/feather
RUN chmod 550 /opt/feather/bin/Feather



## Slim version of the container
FROM swift:5.3.1-focal-slim
WORKDIR /var/feather
COPY --from=builder /opt/feather /opt/feather

RUN \
groupadd -r feather &&\
useradd --no-log-init -r -g feather feather &&\
mkdir -p /var/feather && chown -R feather:feather /var/feather &&\
ln -s /opt/feather/bin/Feather /usr/local/bin/

USER feather

ENV BASE_URL="http://localhost:8080"
ENV BASE_PORT=8080
ENV BASE_PATH="/var/feather"

## Default sqlite
ENV DB_TYPE="sqlite"
ENV MAX_BODYSIZE="10mb"
ENV USE_FILE_MIDDLEWARE="true"

## Using mysql/mariadb/postgres
ENV DB_HOST="localhost"
# ENV DB_PORT=3306 or 5432 # The port will use the default one, if you use a custom port, set this env variable
ENV DB_USER="feather"
ENV DB_PASS="feather"
ENV DB_NAME="feather"

CMD [ "bash", "/opt/feather/start" ]

58 changes: 56 additions & 2 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,24 @@
"version": "1.10.2"
}
},
{
"package": "fluent-mysql-driver",
"repositoryURL": "https://github.com/vapor/fluent-mysql-driver",
"state": {
"branch": null,
"revision": "699e164880387349bf04c2329fe53097524a5904",
"version": "4.0.0"
}
},
{
"package": "fluent-postgres-driver",
"repositoryURL": "https://github.com/vapor/fluent-postgres-driver",
"state": {
"branch": null,
"revision": "11d4fce0c5d8a027a5d131439c9c94dd3230cb8e",
"version": "2.1.2"
}
},
{
"package": "fluent-sqlite-driver",
"repositoryURL": "https://github.com/vapor/fluent-sqlite-driver",
Expand Down Expand Up @@ -244,6 +262,42 @@
"version": "1.0.0-beta.3"
}
},
{
"package": "mysql-kit",
"repositoryURL": "https://github.com/vapor/mysql-kit.git",
"state": {
"branch": null,
"revision": "fe836ecd52815ed1399e654b5365c108ff1638fd",
"version": "4.1.0"
}
},
{
"package": "mysql-nio",
"repositoryURL": "https://github.com/vapor/mysql-nio.git",
"state": {
"branch": null,
"revision": "4cbef4c0903c9792ff1f8dc4b55532276fa70c99",
"version": "1.3.2"
}
},
{
"package": "postgres-kit",
"repositoryURL": "https://github.com/vapor/postgres-kit.git",
"state": {
"branch": null,
"revision": "13f6c735cf9a9053011d03e77e2a81802ad6c680",
"version": "2.3.0"
}
},
{
"package": "postgres-nio",
"repositoryURL": "https://github.com/vapor/postgres-nio.git",
"state": {
"branch": null,
"revision": "2808c4ff334c20073de92e735dac5587ba398b0d",
"version": "1.4.1"
}
},
{
"package": "redirect-module",
"repositoryURL": "https://github.com/FeatherCMS/redirect-module",
Expand Down Expand Up @@ -411,8 +465,8 @@
"repositoryURL": "https://github.com/FeatherCMS/system-module",
"state": {
"branch": null,
"revision": "5d6804551621f154aeb11aaec88870b58bcdee80",
"version": "1.0.0-beta.6"
"revision": "4e10c15c3ed45cdcc2edc67f205daa29b5f23199",
"version": "1.0.0-beta.8"
}
},
{
Expand Down
4 changes: 4 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ let package = Package(
.package(url: "https://github.com/binarybirds/spec.git", from: "1.2.0-beta"),
/// drivers
.package(url: "https://github.com/vapor/fluent-sqlite-driver", from: "4.0.0"),
.package(url: "https://github.com/vapor/fluent-mysql-driver", from: "4.0.0"),
.package(url: "https://github.com/vapor/fluent-postgres-driver", from: "2.0.0"),
.package(url: "https://github.com/binarybirds/liquid-local-driver", from: "1.2.0-beta"),
/// feather core
.package(url: "https://github.com/FeatherCMS/feather-core", from: "1.0.0-beta"),
Expand All @@ -38,6 +40,8 @@ let package = Package(
.target(name: "Feather", dependencies: [
/// drivers
.product(name: "FluentSQLiteDriver", package: "fluent-sqlite-driver"),
.product(name: "FluentMySQLDriver", package: "fluent-mysql-driver"),
.product(name: "FluentPostgresDriver", package: "fluent-postgres-driver"),
.product(name: "LiquidLocalDriver", package: "liquid-local-driver"),
/// feather
.product(name: "FeatherCore", package: "feather-core"),
Expand Down
62 changes: 59 additions & 3 deletions Sources/Feather/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

import FeatherCore
import FluentSQLiteDriver
import FluentMySQLDriver
import FluentPostgresDriver
import LiquidLocalDriver

import SystemModule
Expand All @@ -27,15 +29,68 @@ import MarkdownModule
/// setup metadata delegate object
Feather.metadataDelegate = FrontendMetadataDelegate()

/// Detect the DB type from .env.development or the environement variables
/// # Required:
/// ~~~
/// BASE_URL="http://127.0.0.1:8080"
/// BASE_PATH="/Repo/feather"
/// ~~~
/// # Optional:
/// ~~~
/// MAX_BODYSIZE="10mb" (default) - Required format: XXmb
/// USE_FILE_MIDDLEWARE="true" (default) - Required format: true/false
///
/// DB_TYPE="mysql" # Available: sqlite (default) / mysql / postgres
/// DB_HOST="127.0.0.1"
/// DB_USER="feather"
/// DB_PASS="feather"
/// DB_NAME="feather"
///
/// # Optional: For DB_TYPE = "mysql" | "postgres"
/// DB_PORT=3306 # mysql: 3306 (default) - postgres: 5432(default)
/// ~~~
///
var env = try Environment.detect()
try LoggingSystem.bootstrap(from: &env)
let feather = try Feather(env: env)
defer { feather.stop() }

try feather.configure(database: .sqlite(.file("db.sqlite")),
databaseId: .sqlite,
let dbconfig: DatabaseConfigurationFactory
let dbID: DatabaseID
switch Environment.get("DB_TYPE") {
case "mysql":
dbconfig = .mysql(hostname: Environment.fetch("DB_HOST"),
port: Int(Environment.get("DB_PORT") ?? "3306")!,
username: Environment.fetch("DB_USER"),
password: Environment.fetch("DB_PASS"),
database: Environment.fetch("DB_NAME"),
tlsConfiguration: .forClient(certificateVerification: .none))
dbID = .mysql
break
case "postgres":
dbconfig = .postgres(hostname: Environment.fetch("DB_HOST"),
port: Int(Environment.get("DB_PORT") ?? "5432")!,
username: Environment.fetch("DB_USER"),
password: Environment.fetch("DB_PASS"),
database: Environment.fetch("DB_NAME"))
dbID = .psql
break
default:
dbconfig = .sqlite(.file("db.sqlite"))
dbID = .sqlite
break
}

var middleWare = true
if let provideMiddleWare = Environment.get("USE_FILE_MIDDLEWARE") {
middleWare = Bool(provideMiddleWare) ?? true
}

try feather.configure(database: dbconfig,
databaseId: dbID,
fileStorage: .local(publicUrl: Application.baseUrl, publicPath: Application.Paths.public, workDirectory: "assets"),
fileStorageId: .local,
maxUploadSize: ByteCount(stringLiteral: Environment.get("MAX_BODYSIZE") ?? "10mb"),
modules: [
SystemBuilder(),
UserBuilder(),
Expand All @@ -51,7 +106,8 @@ try feather.configure(database: .sqlite(.file("db.sqlite")),
SponsorBuilder(),
SwiftyBuilder(),
MarkdownBuilder(),
])
],
usePublicFileMiddleware: middleWare)

if feather.app.isDebug {
try feather.reset(resourcesOnly: true)
Expand Down