Commit 90246a9d authored by Mark Harding's avatar Mark Harding
Browse files

(feat): support docker containers

parent 7a93169d
......@@ -28,6 +28,14 @@ Documentation for Minds can be found at [minds.org/docs](https://www.minds.org/d
2. [Testing](https://www.minds.org/docs/testing.html)
3. [Contributing](https://www.minds.org/docs/contributing.html)
## Docker setup
The Docker environment is currently a work in progress and we intend on streamlining the installation phase.
1. Run `docker ps` and look for the minds_php-fpm container
2. Run `docker exec -it CONTAINER_ID_HERE php /var/www/Minds/engine/cli.php install keys`
3. Run `docker exec -it CONTAINER_ID_HERE php /var/www/Minds/engine/cli.php install --graceful-storage-provision --domain=dev.minds.io --username=minds --password=password --email=minds@dev.minds.io --private-key=/.dev/minds.pem --public-key=/.dev/minds.pub --cassandra-server=cassandra`
## Contributing
If you'd like to contribute to the Minds project, check out the [Contribution](https://www.minds.org/docs/contributing.html) section of Minds.org or head right over to the [Minds Open Source Community](https://www.minds.com/groups/profile/365903183068794880). If you've found or fixed a bug, let us know in the [Minds Help and Support Group](https://www.minds.com/groups/profile/100000000000000681/activity)!
......
FROM golang:1.8-alpine
RUN apk add --no-cache git
RUN go get -u \
github.com/aws/aws-sdk-go \
github.com/Sirupsen/logrus \
github.com/joho/godotenv \
github.com/urfave/cli \
github.com/mattn/go-zglob
COPY . .
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -tags netgo -o bin/ecs-deploy
ENV AWS_SDK_LOAD_CONFIG=1
CMD [ "./bin/ecs-deploy" ]
package main
import (
"fmt"
"os"
"github.com/Sirupsen/logrus"
"github.com/joho/godotenv"
"github.com/urfave/cli"
)
var build = "0" // build number set at compile-time
func main() {
app := cli.NewApp()
app.Name = "ecs update plugin"
app.Usage = "ecs update plugin"
app.Action = run
app.Version = fmt.Sprintf("1.0.%s", build)
app.Flags = []cli.Flag{
cli.StringFlag{
Name: "access-key",
Usage: "aws access key",
EnvVar: "PLUGIN_ACCESS_KEY,AWS_ACCESS_KEY_ID",
},
cli.StringFlag{
Name: "secret-key",
Usage: "aws secret key",
EnvVar: "PLUGIN_SECRET_KEY,AWS_SECRET_ACCESS_KEY",
},
cli.StringFlag{
Name: "cluster",
Usage: "ecs cluster name (or arn)",
EnvVar: "PLUGIN_CLUSTER,ECS_CLUSTER",
},
cli.StringFlag{
Name: "region",
Usage: "aws region",
Value: "us-east-1",
EnvVar: "PLUGIN_REGION,ECS_REGION",
},
cli.StringFlag{
Name: "service",
Usage: "service to update",
EnvVar: "PLUGIN_SERVICE,ECS_SERVICE",
},
cli.BoolTFlag{
Name: "yaml-verified",
Usage: "Ensure the yaml was signed",
EnvVar: "DRONE_YAML_VERIFIED",
},
cli.StringFlag{
Name: "env-file",
Usage: "source env file",
},
}
if err := app.Run(os.Args); err != nil {
logrus.Fatal(err)
}
}
func run(c *cli.Context) error {
if c.String("env-file") != "" {
_ = godotenv.Load(c.String("env-file"))
}
plugin := NewPlugin(
c.String("access-key"),
c.String("secret-key"),
c.String("cluster"),
c.String("service"),
c.String("region"),
)
return plugin.Exec()
}
package main
import (
//"mime"
//"os"
"fmt"
//"path/filepath"
//"strings"
//"errors"
//log "github.com/Sirupsen/logrus"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/ecs"
"github.com/aws/aws-sdk-go/service/ecs/ecsiface"
//"github.com/mattn/go-zglob"
)
// Plugin defines the ECS update plugin parameters.
type Plugin struct {
Cluster string
Key string
Secret string
Service string
Region string
Client ecsiface.ECSAPI
}
func NewPlugin(accessKey string, secretKey string, cluster string, service string, region string) *Plugin {
// create the client
conf := &aws.Config{
Region: aws.String(region),
}
//Allowing to use the instance role or provide a key and secret
if accessKey != "" && secretKey != "" {
conf.Credentials = credentials.NewStaticCredentials(accessKey, secretKey, "")
}
client := ecs.New(session.New(), conf)
return &Plugin{
Key: accessKey,
Secret: secretKey,
Cluster: cluster,
Service: service,
Region: region,
Client: client,
}
}
// Exec runs the plugin
func (p *Plugin) Exec() error {
taskDefinition, err := p.getTaskDefinitionFromService();
if err != nil {
fmt.Println("Error", err);
return nil
}
taskDefinitionArn, err := p.updateTaskDefinition(taskDefinition);
if err != nil {
fmt.Println("Error", err);
return nil
}
err = p.updateService(taskDefinitionArn);
if err != nil {
fmt.Println("Error", err);
return nil
}
fmt.Println("Completed");
return nil
}
func (p *Plugin) wait() error {
params := &ecs.DescribeServicesInput{
Services: []*string{
aws.String(p.Service),
},
Cluster: aws.String(p.Cluster),
}
return p.Client.WaitUntilServicesStable(params)
}
func (p *Plugin) updateService(taskDefinitionArn string) error {
params := &ecs.UpdateServiceInput{
Service: aws.String(p.Service),
Cluster: aws.String(p.Cluster),
TaskDefinition: aws.String(taskDefinitionArn),
}
resp, err := p.Client.UpdateService(params)
if err != nil {
return err
}
service := resp.Service
if *service.DesiredCount <= 0 {
return nil
}
return p.wait();
}
func (p *Plugin) updateTaskDefinition(taskDefinition *ecs.TaskDefinition) (string, error) {
params := &ecs.RegisterTaskDefinitionInput{
ContainerDefinitions: taskDefinition.ContainerDefinitions,
Family: taskDefinition.Family,
NetworkMode: taskDefinition.NetworkMode,
PlacementConstraints: taskDefinition.PlacementConstraints,
TaskRoleArn: taskDefinition.TaskRoleArn,
Volumes: taskDefinition.Volumes,
}
resp, err := p.Client.RegisterTaskDefinition(params);
if err != nil {
fmt.Println("Error", err);
return "", err
}
taskDefinitionArn := *resp.TaskDefinition.TaskDefinitionArn;
return taskDefinitionArn, nil
}
func (p *Plugin) getTaskDefinitionFromService() (*ecs.TaskDefinition, error) {
// GET THE SERVICE
params := &ecs.DescribeServicesInput{
Services: []*string{
aws.String(p.Service),
},
Cluster: aws.String(p.Cluster),
}
resp, err := p.Client.DescribeServices(params)
if err != nil {
fmt.Println("Error", err);
return nil, err
}
taskDefinitionArn := *resp.Services[0].Deployments[0].TaskDefinition;
taskDefinition, err := p.getTaskDefinitionFromArn(taskDefinitionArn)
return taskDefinition, err;
}
func (p *Plugin) getTaskDefinitionFromArn(taskDefinitionArn string) (*ecs.TaskDefinition, error) {
//get the task definition
params := &ecs.DescribeTaskDefinitionInput{
TaskDefinition: aws.String(taskDefinitionArn),
}
resp, err := p.Client.DescribeTaskDefinition(params)
if err != nil {
fmt.Println("Error", err);
return nil, err
}
return resp.TaskDefinition, nil;
}
\ No newline at end of file
FROM nginx:1.13-alpine
RUN rm /etc/nginx/conf.d/default.conf
COPY ./minds.conf /etc/nginx/conf.d/minds.conf
\ No newline at end of file
server {
listen 80;
listen [::]:80 default ipv6only=on;
index index.php index.html;
server_name _;
root /var/www/Minds/front/public;
error_log /dev/stdout info;
sendfile off;
location / {
try_files $uri $uri/ @rewrite;
}
location ~ ^(/api|/fs|/icon|/carousel) {
add_header 'Access-Control-Allow-Origin' "$http_origin";
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Mx-ReqToken,X-Requested-With';
set $cors "api";
rewrite ^(.+)$ /index.php last;
}
location @rewrite {
rewrite ^(.+)$ /index.php last;
}
# pass the PHP scripts to FastCGI server listening on socket
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass php-fpm:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME /var/www/Minds/engine/index.php;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
location ~* \.(jpg|jpeg|gif|png|css|js|ico|xml)$ {
expires 5d;
}
location ~ /\. {
log_not_found off;
deny all;
}
}
\ No newline at end of file
FROM alpine
## Copy plugins
ADD plugins plugins
\ No newline at end of file
FROM alpine:latest
RUN apk add --no-cache python py-pip && \
pip install awscli
COPY sync.sh .
RUN [ "chmod", "+x", "sync.sh" ]
ENTRYPOINT '/sync.sh'
CMD [ "" ]
\ No newline at end of file
#!/bin/sh
echo "SYNCING: $S3_BUCKET"
aws s3 sync $S3_BUCKET $DIR
echo "DONE"
\ No newline at end of file
# Using v2.2 because v3+ is meant for swarm operations
version: "2.2"
services:
cassandra:
image: cassandra:3.11
environment:
- CASSANDRA_START_RPC=true
networks:
- app
mongo:
image: mongo:3.4
networks:
- app
elasticsearch:
image: elasticsearch:5.6-alpine
mem_limit: 512MB # keep an eye
ulimits:
memlock:
soft: -1
hard: -1
environment:
- "ES_JAVA_OPTS=-Xms256m -Xmx256m"
networks:
- app
redis:
image: redis:4.0-alpine
mem_limit: 256MB # keep an eye
networks:
- app
rabbitmq:
image: rabbitmq:3.6-alpine
networks:
- app
php-fpm:
build:
context: ./engine
dockerfile: ./containers/php-fpm/Dockerfile
depends_on:
- cassandra
- mongo
- elasticsearch
- rabbitmq
- redis
networks:
- app
volumes:
## The following is for development environments only. Comment out on production. ##
- "./front/:/var/www/Minds/front"
- "./plugins/:/var/www/Minds/plugins"
- "./languages/:/var/www/Minds/languages"
## The following is for development environments only. Comment out on production. ##
- "./engine/:/var/www/Minds/engine"
runners:
build:
context: ./engine
dockerfile: ./containers/php-fpm/Dockerfile
depends_on:
- cassandra
# - mongo
# - elasticsearch
# - rabbitmq
- redis
networks:
- app
volumes:
- "./front/:/var/www/Minds/front"
- "./plugins/:/var/www/Minds/plugins"
- "./languages/:/var/www/Minds/languages"
nginx:
build:
context: ./containers/nginx
depends_on:
- php-fpm
ports:
- "8080:80"
networks:
- app
volumes:
## The following is for development environments only. Comment out on production. ##
- "./front/:/var/www/Minds/front"
networks:
app:
driver: "bridge"
Subproject commit 4728a4123f85054b41fdf7f6b198b58b74653c35
Subproject commit 15031b83b0d20f90a1da1adf615c28a3a5410441
Subproject commit a1f8981d359c2e6f33ba8c6a2fe9d93458c19173
Subproject commit 15bace5abe40367a797b0e70f457155d7fa12df6
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment