├── .docker ├── app.env ├── entrypoint ├── mysql.env ├── sphinx.conf └── waitfortcp ├── .dockerignore ├── .gitignore ├── Dockerfile ├── README.md └── docker-compose.yml /.docker/app.env: -------------------------------------------------------------------------------- 1 | RAILS_DB_ADAPTER=mysql2 2 | RAILS_DB_HOST=db 3 | RAILS_DB_PORT=3306 4 | RAILS_DB_USERNAME=hitobito 5 | RAILS_DB_PASSWORD=hitobito 6 | RAILS_DB_NAME=hitobito 7 | MEMCACHE_SERVERS=cache 8 | RAILS_MAIL_DELIVERY_METHOD=smtp 9 | RAILS_MAIL_DELIVERY_CONFIG=address: mail, port: 1025 10 | RAILS_SPHINX_HOST=sphinx 11 | -------------------------------------------------------------------------------- /.docker/entrypoint: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set +e 4 | 5 | echo "⚙️ Testing DB connection" 6 | timeout 300s waitfortcp "${RAILS_DB_HOST-db}" "${RAILS_DB_PORT-3306}" 7 | echo "✅ DB is ready" 8 | 9 | if [ "$RAILS_ENV" != "production" ]; then 10 | echo "⚙️ Performing migrations" 11 | bundle exec rake db:migrate wagon:migrate 12 | echo "✅ Migrations done" 13 | else 14 | echo "↪️ Skipping migrations because RAILS_ENV='$RAILS_ENV'" 15 | fi 16 | 17 | if [ "$RAILS_ENV" == "development" ]; then 18 | if [ ! -f /seed/done ]; then 19 | echo "⚙️ Seeding DB" 20 | bundle exec rake db:seed wagon:seed && date > /seed/done 21 | echo "✅ Seeding done" 22 | else 23 | echo "↪️ Skipping seeding because already done on $(cat /seed/done)" 24 | fi 25 | else 26 | echo "↪️ Skipping seeding because RAILS_ENV='$RAILS_ENV'" 27 | fi 28 | 29 | echo "➡️ Handing control over to '$*''" 30 | 31 | # shellcheck disable=SC2068 32 | exec bundle exec $@ 33 | -------------------------------------------------------------------------------- /.docker/mysql.env: -------------------------------------------------------------------------------- 1 | MYSQL_ROOT_PASSWORD=root 2 | MYSQL_DATABASE=hitobito 3 | MYSQL_USER=hitobito 4 | MYSQL_PASSWORD=hitobito 5 | -------------------------------------------------------------------------------- /.docker/sphinx.conf: -------------------------------------------------------------------------------- 1 | indexer 2 | { 3 | } 4 | 5 | searchd 6 | { 7 | listen = 0.0.0.0:9312:mysql41 8 | log = /opt/sphinx/log/searchd.log 9 | query_log = /opt/sphinx/log/searchd.query.log 10 | pid_file = /opt/sphinx/log/sphinx.pid 11 | max_filter_values = 1048576 12 | workers = threads 13 | binlog_path = /opt/sphinx/log 14 | } 15 | 16 | source person_core_0 17 | { 18 | type = mysql 19 | sql_host = db 20 | sql_user = hitobito 21 | sql_pass = hitobito 22 | sql_db = hitobito 23 | sql_port = 3306 24 | sql_query_pre = SET TIME_ZONE = '+0:00' 25 | sql_query_pre = SET NAMES utf8 26 | sql_query = SELECT SQL_NO_CACHE `people`.`id` * 3 + 0 AS `id`, 'Person' AS `sphinx_internal_class_name`, `people`.`number` AS `number`, `people`.`salutation` AS `salutation`, `people`.`canton` AS `canton`, `people`.`first_name` AS `first_name`, `people`.`last_name` AS `last_name`, `people`.`company_name` AS `company_name`, `people`.`nickname` AS `nickname`, `people`.`company` AS `company`, `people`.`email` AS `email`, `people`.`address` AS `address`, `people`.`zip_code` AS `zip_code`, `people`.`town` AS `town`, `people`.`country` AS `country`, `people`.`birthday` AS `birthday`, `people`.`additional_information` AS `additional_information`, GROUP_CONCAT(DISTINCT `phone_numbers`.`number` SEPARATOR ' ') AS `phone_number`, GROUP_CONCAT(DISTINCT `social_accounts`.`name` SEPARATOR ' ') AS `social_account`, GROUP_CONCAT(DISTINCT `additional_emails`.`email` SEPARATOR ' ') AS `additional_email`, `people`.`id` AS `sphinx_internal_id`, 'Person' AS `sphinx_internal_class`, 0 AS `sphinx_deleted` FROM `people` LEFT OUTER JOIN `phone_numbers` ON `phone_numbers`.`contactable_id` = `people`.`id` AND `phone_numbers`.`contactable_type` = 'Person' LEFT OUTER JOIN `social_accounts` ON `social_accounts`.`contactable_id` = `people`.`id` AND `social_accounts`.`contactable_type` = 'Person' LEFT OUTER JOIN `additional_emails` ON `additional_emails`.`contactable_id` = `people`.`id` AND `additional_emails`.`contactable_type` = 'Person' WHERE (`people`.`id` BETWEEN $start AND $end) GROUP BY `people`.`id`, `people`.`number`, `people`.`salutation`, `people`.`canton`, `people`.`first_name`, `people`.`last_name`, `people`.`company_name`, `people`.`nickname`, `people`.`company`, `people`.`email`, `people`.`address`, `people`.`zip_code`, `people`.`town`, `people`.`country`, `people`.`birthday`, `people`.`additional_information`, `people`.`id` ORDER BY NULL 27 | sql_query_range = SELECT IFNULL(MIN(`people`.`id`), 1), IFNULL(MAX(`people`.`id`), 1) FROM `people` 28 | sql_attr_uint = sphinx_internal_id 29 | sql_attr_uint = sphinx_deleted 30 | sql_attr_string = sphinx_internal_class 31 | sql_field_string = first_name 32 | sql_field_string = last_name 33 | sql_field_string = company_name 34 | sql_field_string = nickname 35 | sql_field_string = company 36 | sql_field_string = email 37 | } 38 | 39 | index person_core 40 | { 41 | type = plain 42 | path = /opt/sphinx/index/person_core 43 | charset_table = 0..9, a..z, _, -, U+002E->., U+003A, A..Z->a..z, U+00C0->a, U+00C1->a, U+00C2->a, U+00C3->a, U+00C4->a, U+00C5->a, U+00C7->c, U+00C8->e, U+00C9->e, U+00CA->e, U+00CB->e, U+00CC->i, U+00CD->i, U+00CE->i, U+00CF->i, U+00D1->n, U+00D2->o, U+00D3->o, U+00D4->o, U+00D5->o, U+00D6->o, U+00D9->u, U+00DA->u, U+00DB->u, U+00DC->u, U+00DD->y, U+00E0->a, U+00E1->a, U+00E2->a, U+00E3->a, U+00E4->a, U+00E5->a, U+00E7->c, U+00E8->e, U+00E9->e, U+00EA->e, U+00EB->e, U+00EC->i, U+00ED->i, U+00EE->i, U+00EF->i, U+00F1->n, U+00F2->o, U+00F3->o, U+00F4->o, U+00F5->o, U+00F6->o, U+00F9->u, U+00FA->u, U+00FB->u, U+00FC->u, U+00FD->y, U+00FF->y, U+0100->a, U+0101->a, U+0102->a, U+0103->a, U+0104->a, U+0105->a, U+0106->c, U+0107->c, U+0108->c, U+0109->c, U+010A->c, U+010B->c, U+010C->c, U+010D->c, U+010E->d, U+010F->d, U+0112->e, U+0113->e, U+0114->e, U+0115->e, U+0116->e, U+0117->e, U+0118->e, U+0119->e, U+011A->e, U+011B->e, U+011C->g, U+011D->g, U+011E->g, U+011F->g, U+0120->g, U+0121->g, U+0122->g, U+0123->g, U+0124->h, U+0125->h, U+0128->i, U+0129->i, U+012A->i, U+012B->i, U+012C->i, U+012D->i, U+012E->i, U+012F->i, U+0130->i, U+0134->j, U+0135->j, U+0136->k, U+0137->k, U+0139->l, U+013A->l, U+013B->l, U+013C->l, U+013D->l, U+013E->l, U+0142->l, U+0143->n, U+0144->n, U+0145->n, U+0146->n, U+0147->n, U+0148->n, U+014C->o, U+014D->o, U+014E->o, U+014F->o, U+0150->o, U+0151->o, U+0154->r, U+0155->r, U+0156->r, U+0157->r, U+0158->r, U+0159->r, U+015A->s, U+015B->s, U+015C->s, U+015D->s, U+015E->s, U+015F->s, U+0160->s, U+0161->s, U+0162->t, U+0163->t, U+0164->t, U+0165->t, U+0168->u, U+0169->u, U+016A->u, U+016B->u, U+016C->u, U+016D->u, U+016E->u, U+016F->u, U+0170->u, U+0171->u, U+0172->u, U+0173->u, U+0174->w, U+0175->w, U+0176->y, U+0177->y, U+0178->y, U+0179->z, U+017A->z, U+017B->z, U+017C->z, U+017D->z, U+017E->z, U+01A0->o, U+01A1->o, U+01AF->u, U+01B0->u, U+01CD->a, U+01CE->a, U+01CF->i, U+01D0->i, U+01D1->o, U+01D2->o, U+01D3->u, U+01D4->u, U+01D5->u, U+01D6->u, U+01D7->u, U+01D8->u, U+01D9->u, U+01DA->u, U+01DB->u, U+01DC->u, U+01DE->a, U+01DF->a, U+01E0->a, U+01E1->a, U+01E6->g, U+01E7->g, U+01E8->k, U+01E9->k, U+01EA->o, U+01EB->o, U+01EC->o, U+01ED->o, U+01F0->j, U+01F4->g, U+01F5->g, U+01F8->n, U+01F9->n, U+01FA->a, U+01FB->a, U+0200->a, U+0201->a, U+0202->a, U+0203->a, U+0204->e, U+0205->e, U+0206->e, U+0207->e, U+0208->i, U+0209->i, U+020A->i, U+020B->i, U+020C->o, U+020D->o, U+020E->o, U+020F->o, U+0210->r, U+0211->r, U+0212->r, U+0213->r, U+0214->u, U+0215->u, U+0216->u, U+0217->u, U+0218->s, U+0219->s, U+021A->t, U+021B->t, U+021E->h, U+021F->h, U+0226->a, U+0227->a, U+0228->e, U+0229->e, U+022A->o, U+022B->o, U+022C->o, U+022D->o, U+022E->o, U+022F->o, U+0230->o, U+0231->o, U+0232->y, U+0233->y, U+1E00->a, U+1E01->a, U+1E02->b, U+1E03->b, U+1E04->b, U+1E05->b, U+1E06->b, U+1E07->b, U+1E08->c, U+1E09->c, U+1E0A->d, U+1E0B->d, U+1E0C->d, U+1E0D->d, U+1E0E->d, U+1E0F->d, U+1E10->d, U+1E11->d, U+1E12->d, U+1E13->d, U+1E14->e, U+1E15->e, U+1E16->e, U+1E17->e, U+1E18->e, U+1E19->e, U+1E1A->e, U+1E1B->e, U+1E1C->e, U+1E1D->e, U+1E1E->f, U+1E1F->f, U+1E20->g, U+1E21->g, U+1E22->h, U+1E23->h, U+1E24->h, U+1E25->h, U+1E26->h, U+1E27->h, U+1E28->h, U+1E29->h, U+1E2A->h, U+1E2B->h, U+1E2C->i, U+1E2D->i, U+1E2E->i, U+1E2F->i, U+1E30->k, U+1E31->k, U+1E32->k, U+1E33->k, U+1E34->k, U+1E35->k, U+1E36->l, U+1E37->l, U+1E38->l, U+1E39->l, U+1E3A->l, U+1E3B->l, U+1E3C->l, U+1E3D->l, U+1E3E->m, U+1E3F->m, U+1E40->m, U+1E41->m, U+1E42->m, U+1E43->m, U+1E44->n, U+1E45->n, U+1E46->n, U+1E47->n, U+1E48->n, U+1E49->n, U+1E4A->n, U+1E4B->n, U+1E4C->o, U+1E4D->o, U+1E4E->o, U+1E4F->o, U+1E50->o, U+1E51->o, U+1E52->o, U+1E53->o, U+1E54->p, U+1E55->p, U+1E56->p, U+1E57->p, U+1E58->r, U+1E59->r, U+1E5A->r, U+1E5B->r, U+1E5C->r, U+1E5D->r, U+1E5E->r, U+1E5F->r, U+1E60->s, U+1E61->s, U+1E62->s, U+1E63->s, U+1E64->s, U+1E65->s, U+1E66->s, U+1E67->s, U+1E68->s, U+1E69->s, U+1E6A->t, U+1E6B->t, U+1E6C->t, U+1E6D->t, U+1E6E->t, U+1E6F->t, U+1E70->t, U+1E71->t, U+1E72->u, U+1E73->u, U+1E74->u, U+1E75->u, U+1E76->u, U+1E77->u, U+1E78->u, U+1E79->u, U+1E7A->u, U+1E7B->u, U+1E7C->v, U+1E7D->v, U+1E7E->v, U+1E7F->v, U+1E80->w, U+1E81->w, U+1E82->w, U+1E83->w, U+1E84->w, U+1E85->w, U+1E86->w, U+1E87->w, U+1E88->w, U+1E89->w, U+1E8A->x, U+1E8B->x, U+1E8C->x, U+1E8D->x, U+1E8E->y, U+1E8F->y, U+1E96->h, U+1E97->t, U+1E98->w, U+1E99->y, U+1EA0->a, U+1EA1->a, U+1EA2->a, U+1EA3->a, U+1EA4->a, U+1EA5->a, U+1EA6->a, U+1EA7->a, U+1EA8->a, U+1EA9->a, U+1EAA->a, U+1EAB->a, U+1EAC->a, U+1EAD->a, U+1EAE->a, U+1EAF->a, U+1EB0->a, U+1EB1->a, U+1EB2->a, U+1EB3->a, U+1EB4->a, U+1EB5->a, U+1EB6->a, U+1EB7->a, U+1EB8->e, U+1EB9->e, U+1EBA->e, U+1EBB->e, U+1EBC->e, U+1EBD->e, U+1EBE->e, U+1EBF->e, U+1EC0->e, U+1EC1->e, U+1EC2->e, U+1EC3->e, U+1EC4->e, U+1EC5->e, U+1EC6->e, U+1EC7->e, U+1EC8->i, U+1EC9->i, U+1ECA->i, U+1ECB->i, U+1ECC->o, U+1ECD->o, U+1ECE->o, U+1ECF->o, U+1ED0->o, U+1ED1->o, U+1ED2->o, U+1ED3->o, U+1ED4->o, U+1ED5->o, U+1ED6->o, U+1ED7->o, U+1ED8->o, U+1ED9->o, U+1EDA->o, U+1EDB->o, U+1EDC->o, U+1EDD->o, U+1EDE->o, U+1EDF->o, U+1EE0->o, U+1EE1->o, U+1EE2->o, U+1EE3->o, U+1EE4->u, U+1EE5->u, U+1EE6->u, U+1EE7->u, U+1EE8->u, U+1EE9->u, U+1EEA->u, U+1EEB->u, U+1EEC->u, U+1EED->u, U+1EEE->u, U+1EEF->u, U+1EF0->u, U+1EF1->u, U+1EF2->y, U+1EF3->y, U+1EF4->y, U+1EF5->y, U+1EF6->y, U+1EF7->y, U+1EF8->y, U+1EF9->y 44 | min_infix_len = 2 45 | html_strip = 1 46 | source = person_core_0 47 | } 48 | 49 | source event_core_0 50 | { 51 | type = mysql 52 | sql_host = db 53 | sql_user = hitobito 54 | sql_pass = hitobito 55 | sql_db = hitobito 56 | sql_port = 3306 57 | sql_query_pre = SET TIME_ZONE = '+0:00' 58 | sql_query_pre = SET NAMES utf8 59 | sql_query = SELECT SQL_NO_CACHE `events`.`id` * 3 + 1 AS `id`, COALESCE(NULLIF(`events`.`type`, ''), 'Event') AS `sphinx_internal_class_name`, `events`.`name` AS `name`, `events`.`number` AS `number`, GROUP_CONCAT(DISTINCT `groups`.`name` SEPARATOR ' ') AS `group_name`, `events`.`id` AS `sphinx_internal_id`, COALESCE(NULLIF(`events`.`type`, ''), 'Event') AS `sphinx_internal_class`, 0 AS `sphinx_deleted` FROM `events` LEFT OUTER JOIN `events_groups` ON `events_groups`.`event_id` = `events`.`id` LEFT OUTER JOIN `groups` ON `groups`.`id` = `events_groups`.`group_id` WHERE (`events`.`id` BETWEEN $start AND $end) GROUP BY `events`.`id`, `events`.`name`, `events`.`number`, `events`.`id`, `events`.`type` ORDER BY NULL 60 | sql_query_range = SELECT IFNULL(MIN(`events`.`id`), 1), IFNULL(MAX(`events`.`id`), 1) FROM `events` 61 | sql_attr_uint = sphinx_internal_id 62 | sql_attr_uint = sphinx_deleted 63 | sql_attr_string = sphinx_internal_class 64 | sql_field_string = name 65 | sql_field_string = number 66 | } 67 | 68 | index event_core 69 | { 70 | type = plain 71 | path = /opt/sphinx/index/event_core 72 | charset_table = 0..9, a..z, _, -, U+002E->., U+003A, A..Z->a..z, U+00C0->a, U+00C1->a, U+00C2->a, U+00C3->a, U+00C4->a, U+00C5->a, U+00C7->c, U+00C8->e, U+00C9->e, U+00CA->e, U+00CB->e, U+00CC->i, U+00CD->i, U+00CE->i, U+00CF->i, U+00D1->n, U+00D2->o, U+00D3->o, U+00D4->o, U+00D5->o, U+00D6->o, U+00D9->u, U+00DA->u, U+00DB->u, U+00DC->u, U+00DD->y, U+00E0->a, U+00E1->a, U+00E2->a, U+00E3->a, U+00E4->a, U+00E5->a, U+00E7->c, U+00E8->e, U+00E9->e, U+00EA->e, U+00EB->e, U+00EC->i, U+00ED->i, U+00EE->i, U+00EF->i, U+00F1->n, U+00F2->o, U+00F3->o, U+00F4->o, U+00F5->o, U+00F6->o, U+00F9->u, U+00FA->u, U+00FB->u, U+00FC->u, U+00FD->y, U+00FF->y, U+0100->a, U+0101->a, U+0102->a, U+0103->a, U+0104->a, U+0105->a, U+0106->c, U+0107->c, U+0108->c, U+0109->c, U+010A->c, U+010B->c, U+010C->c, U+010D->c, U+010E->d, U+010F->d, U+0112->e, U+0113->e, U+0114->e, U+0115->e, U+0116->e, U+0117->e, U+0118->e, U+0119->e, U+011A->e, U+011B->e, U+011C->g, U+011D->g, U+011E->g, U+011F->g, U+0120->g, U+0121->g, U+0122->g, U+0123->g, U+0124->h, U+0125->h, U+0128->i, U+0129->i, U+012A->i, U+012B->i, U+012C->i, U+012D->i, U+012E->i, U+012F->i, U+0130->i, U+0134->j, U+0135->j, U+0136->k, U+0137->k, U+0139->l, U+013A->l, U+013B->l, U+013C->l, U+013D->l, U+013E->l, U+0142->l, U+0143->n, U+0144->n, U+0145->n, U+0146->n, U+0147->n, U+0148->n, U+014C->o, U+014D->o, U+014E->o, U+014F->o, U+0150->o, U+0151->o, U+0154->r, U+0155->r, U+0156->r, U+0157->r, U+0158->r, U+0159->r, U+015A->s, U+015B->s, U+015C->s, U+015D->s, U+015E->s, U+015F->s, U+0160->s, U+0161->s, U+0162->t, U+0163->t, U+0164->t, U+0165->t, U+0168->u, U+0169->u, U+016A->u, U+016B->u, U+016C->u, U+016D->u, U+016E->u, U+016F->u, U+0170->u, U+0171->u, U+0172->u, U+0173->u, U+0174->w, U+0175->w, U+0176->y, U+0177->y, U+0178->y, U+0179->z, U+017A->z, U+017B->z, U+017C->z, U+017D->z, U+017E->z, U+01A0->o, U+01A1->o, U+01AF->u, U+01B0->u, U+01CD->a, U+01CE->a, U+01CF->i, U+01D0->i, U+01D1->o, U+01D2->o, U+01D3->u, U+01D4->u, U+01D5->u, U+01D6->u, U+01D7->u, U+01D8->u, U+01D9->u, U+01DA->u, U+01DB->u, U+01DC->u, U+01DE->a, U+01DF->a, U+01E0->a, U+01E1->a, U+01E6->g, U+01E7->g, U+01E8->k, U+01E9->k, U+01EA->o, U+01EB->o, U+01EC->o, U+01ED->o, U+01F0->j, U+01F4->g, U+01F5->g, U+01F8->n, U+01F9->n, U+01FA->a, U+01FB->a, U+0200->a, U+0201->a, U+0202->a, U+0203->a, U+0204->e, U+0205->e, U+0206->e, U+0207->e, U+0208->i, U+0209->i, U+020A->i, U+020B->i, U+020C->o, U+020D->o, U+020E->o, U+020F->o, U+0210->r, U+0211->r, U+0212->r, U+0213->r, U+0214->u, U+0215->u, U+0216->u, U+0217->u, U+0218->s, U+0219->s, U+021A->t, U+021B->t, U+021E->h, U+021F->h, U+0226->a, U+0227->a, U+0228->e, U+0229->e, U+022A->o, U+022B->o, U+022C->o, U+022D->o, U+022E->o, U+022F->o, U+0230->o, U+0231->o, U+0232->y, U+0233->y, U+1E00->a, U+1E01->a, U+1E02->b, U+1E03->b, U+1E04->b, U+1E05->b, U+1E06->b, U+1E07->b, U+1E08->c, U+1E09->c, U+1E0A->d, U+1E0B->d, U+1E0C->d, U+1E0D->d, U+1E0E->d, U+1E0F->d, U+1E10->d, U+1E11->d, U+1E12->d, U+1E13->d, U+1E14->e, U+1E15->e, U+1E16->e, U+1E17->e, U+1E18->e, U+1E19->e, U+1E1A->e, U+1E1B->e, U+1E1C->e, U+1E1D->e, U+1E1E->f, U+1E1F->f, U+1E20->g, U+1E21->g, U+1E22->h, U+1E23->h, U+1E24->h, U+1E25->h, U+1E26->h, U+1E27->h, U+1E28->h, U+1E29->h, U+1E2A->h, U+1E2B->h, U+1E2C->i, U+1E2D->i, U+1E2E->i, U+1E2F->i, U+1E30->k, U+1E31->k, U+1E32->k, U+1E33->k, U+1E34->k, U+1E35->k, U+1E36->l, U+1E37->l, U+1E38->l, U+1E39->l, U+1E3A->l, U+1E3B->l, U+1E3C->l, U+1E3D->l, U+1E3E->m, U+1E3F->m, U+1E40->m, U+1E41->m, U+1E42->m, U+1E43->m, U+1E44->n, U+1E45->n, U+1E46->n, U+1E47->n, U+1E48->n, U+1E49->n, U+1E4A->n, U+1E4B->n, U+1E4C->o, U+1E4D->o, U+1E4E->o, U+1E4F->o, U+1E50->o, U+1E51->o, U+1E52->o, U+1E53->o, U+1E54->p, U+1E55->p, U+1E56->p, U+1E57->p, U+1E58->r, U+1E59->r, U+1E5A->r, U+1E5B->r, U+1E5C->r, U+1E5D->r, U+1E5E->r, U+1E5F->r, U+1E60->s, U+1E61->s, U+1E62->s, U+1E63->s, U+1E64->s, U+1E65->s, U+1E66->s, U+1E67->s, U+1E68->s, U+1E69->s, U+1E6A->t, U+1E6B->t, U+1E6C->t, U+1E6D->t, U+1E6E->t, U+1E6F->t, U+1E70->t, U+1E71->t, U+1E72->u, U+1E73->u, U+1E74->u, U+1E75->u, U+1E76->u, U+1E77->u, U+1E78->u, U+1E79->u, U+1E7A->u, U+1E7B->u, U+1E7C->v, U+1E7D->v, U+1E7E->v, U+1E7F->v, U+1E80->w, U+1E81->w, U+1E82->w, U+1E83->w, U+1E84->w, U+1E85->w, U+1E86->w, U+1E87->w, U+1E88->w, U+1E89->w, U+1E8A->x, U+1E8B->x, U+1E8C->x, U+1E8D->x, U+1E8E->y, U+1E8F->y, U+1E96->h, U+1E97->t, U+1E98->w, U+1E99->y, U+1EA0->a, U+1EA1->a, U+1EA2->a, U+1EA3->a, U+1EA4->a, U+1EA5->a, U+1EA6->a, U+1EA7->a, U+1EA8->a, U+1EA9->a, U+1EAA->a, U+1EAB->a, U+1EAC->a, U+1EAD->a, U+1EAE->a, U+1EAF->a, U+1EB0->a, U+1EB1->a, U+1EB2->a, U+1EB3->a, U+1EB4->a, U+1EB5->a, U+1EB6->a, U+1EB7->a, U+1EB8->e, U+1EB9->e, U+1EBA->e, U+1EBB->e, U+1EBC->e, U+1EBD->e, U+1EBE->e, U+1EBF->e, U+1EC0->e, U+1EC1->e, U+1EC2->e, U+1EC3->e, U+1EC4->e, U+1EC5->e, U+1EC6->e, U+1EC7->e, U+1EC8->i, U+1EC9->i, U+1ECA->i, U+1ECB->i, U+1ECC->o, U+1ECD->o, U+1ECE->o, U+1ECF->o, U+1ED0->o, U+1ED1->o, U+1ED2->o, U+1ED3->o, U+1ED4->o, U+1ED5->o, U+1ED6->o, U+1ED7->o, U+1ED8->o, U+1ED9->o, U+1EDA->o, U+1EDB->o, U+1EDC->o, U+1EDD->o, U+1EDE->o, U+1EDF->o, U+1EE0->o, U+1EE1->o, U+1EE2->o, U+1EE3->o, U+1EE4->u, U+1EE5->u, U+1EE6->u, U+1EE7->u, U+1EE8->u, U+1EE9->u, U+1EEA->u, U+1EEB->u, U+1EEC->u, U+1EED->u, U+1EEE->u, U+1EEF->u, U+1EF0->u, U+1EF1->u, U+1EF2->y, U+1EF3->y, U+1EF4->y, U+1EF5->y, U+1EF6->y, U+1EF7->y, U+1EF8->y, U+1EF9->y 73 | min_infix_len = 2 74 | html_strip = 1 75 | source = event_core_0 76 | } 77 | 78 | source group_core_0 79 | { 80 | type = mysql 81 | sql_host = db 82 | sql_user = hitobito 83 | sql_pass = hitobito 84 | sql_db = hitobito 85 | sql_port = 3306 86 | sql_query_pre = SET TIME_ZONE = '+0:00' 87 | sql_query_pre = SET NAMES utf8 88 | sql_query = SELECT SQL_NO_CACHE `groups`.`id` * 3 + 2 AS `id`, COALESCE(NULLIF(`groups`.`type`, ''), 'Group') AS `sphinx_internal_class_name`, `groups`.`name` AS `name`, `groups`.`short_name` AS `short_name`, `groups`.`email` AS `email`, `groups`.`address` AS `address`, `groups`.`zip_code` AS `zip_code`, `groups`.`town` AS `town`, `groups`.`country` AS `country`, `parents_groups`.`name` AS `parent_name`, `parents_groups`.`short_name` AS `parent_short_name`, GROUP_CONCAT(DISTINCT `phone_numbers`.`number` SEPARATOR ' ') AS `phone_number`, GROUP_CONCAT(DISTINCT `social_accounts`.`name` SEPARATOR ' ') AS `social_account`, GROUP_CONCAT(DISTINCT `additional_emails`.`email` SEPARATOR ' ') AS `additional_email`, `groups`.`id` AS `sphinx_internal_id`, COALESCE(NULLIF(`groups`.`type`, ''), 'Group') AS `sphinx_internal_class`, 0 AS `sphinx_deleted` FROM `groups` LEFT OUTER JOIN `groups` `parents_groups` ON `parents_groups`.`id` = `groups`.`parent_id` LEFT OUTER JOIN `phone_numbers` ON `phone_numbers`.`contactable_id` = `groups`.`id` AND `phone_numbers`.`contactable_type` = 'Group' LEFT OUTER JOIN `social_accounts` ON `social_accounts`.`contactable_id` = `groups`.`id` AND `social_accounts`.`contactable_type` = 'Group' LEFT OUTER JOIN `additional_emails` ON `additional_emails`.`contactable_id` = `groups`.`id` AND `additional_emails`.`contactable_type` = 'Group' WHERE (`groups`.`id` BETWEEN $start AND $end AND groups.deleted_at IS NULL) GROUP BY `groups`.`id`, `groups`.`name`, `groups`.`short_name`, `groups`.`email`, `groups`.`address`, `groups`.`zip_code`, `groups`.`town`, `groups`.`country`, `parents_groups`.`name`, `parents_groups`.`short_name`, `groups`.`id`, `groups`.`type` ORDER BY NULL 89 | sql_query_range = SELECT IFNULL(MIN(`groups`.`id`), 1), IFNULL(MAX(`groups`.`id`), 1) FROM `groups` 90 | sql_attr_uint = sphinx_internal_id 91 | sql_attr_uint = sphinx_deleted 92 | sql_attr_string = sphinx_internal_class 93 | sql_field_string = name 94 | sql_field_string = short_name 95 | } 96 | 97 | index group_core 98 | { 99 | type = plain 100 | path = /opt/sphinx/index/group_core 101 | charset_table = 0..9, a..z, _, -, U+002E->., U+003A, A..Z->a..z, U+00C0->a, U+00C1->a, U+00C2->a, U+00C3->a, U+00C4->a, U+00C5->a, U+00C7->c, U+00C8->e, U+00C9->e, U+00CA->e, U+00CB->e, U+00CC->i, U+00CD->i, U+00CE->i, U+00CF->i, U+00D1->n, U+00D2->o, U+00D3->o, U+00D4->o, U+00D5->o, U+00D6->o, U+00D9->u, U+00DA->u, U+00DB->u, U+00DC->u, U+00DD->y, U+00E0->a, U+00E1->a, U+00E2->a, U+00E3->a, U+00E4->a, U+00E5->a, U+00E7->c, U+00E8->e, U+00E9->e, U+00EA->e, U+00EB->e, U+00EC->i, U+00ED->i, U+00EE->i, U+00EF->i, U+00F1->n, U+00F2->o, U+00F3->o, U+00F4->o, U+00F5->o, U+00F6->o, U+00F9->u, U+00FA->u, U+00FB->u, U+00FC->u, U+00FD->y, U+00FF->y, U+0100->a, U+0101->a, U+0102->a, U+0103->a, U+0104->a, U+0105->a, U+0106->c, U+0107->c, U+0108->c, U+0109->c, U+010A->c, U+010B->c, U+010C->c, U+010D->c, U+010E->d, U+010F->d, U+0112->e, U+0113->e, U+0114->e, U+0115->e, U+0116->e, U+0117->e, U+0118->e, U+0119->e, U+011A->e, U+011B->e, U+011C->g, U+011D->g, U+011E->g, U+011F->g, U+0120->g, U+0121->g, U+0122->g, U+0123->g, U+0124->h, U+0125->h, U+0128->i, U+0129->i, U+012A->i, U+012B->i, U+012C->i, U+012D->i, U+012E->i, U+012F->i, U+0130->i, U+0134->j, U+0135->j, U+0136->k, U+0137->k, U+0139->l, U+013A->l, U+013B->l, U+013C->l, U+013D->l, U+013E->l, U+0142->l, U+0143->n, U+0144->n, U+0145->n, U+0146->n, U+0147->n, U+0148->n, U+014C->o, U+014D->o, U+014E->o, U+014F->o, U+0150->o, U+0151->o, U+0154->r, U+0155->r, U+0156->r, U+0157->r, U+0158->r, U+0159->r, U+015A->s, U+015B->s, U+015C->s, U+015D->s, U+015E->s, U+015F->s, U+0160->s, U+0161->s, U+0162->t, U+0163->t, U+0164->t, U+0165->t, U+0168->u, U+0169->u, U+016A->u, U+016B->u, U+016C->u, U+016D->u, U+016E->u, U+016F->u, U+0170->u, U+0171->u, U+0172->u, U+0173->u, U+0174->w, U+0175->w, U+0176->y, U+0177->y, U+0178->y, U+0179->z, U+017A->z, U+017B->z, U+017C->z, U+017D->z, U+017E->z, U+01A0->o, U+01A1->o, U+01AF->u, U+01B0->u, U+01CD->a, U+01CE->a, U+01CF->i, U+01D0->i, U+01D1->o, U+01D2->o, U+01D3->u, U+01D4->u, U+01D5->u, U+01D6->u, U+01D7->u, U+01D8->u, U+01D9->u, U+01DA->u, U+01DB->u, U+01DC->u, U+01DE->a, U+01DF->a, U+01E0->a, U+01E1->a, U+01E6->g, U+01E7->g, U+01E8->k, U+01E9->k, U+01EA->o, U+01EB->o, U+01EC->o, U+01ED->o, U+01F0->j, U+01F4->g, U+01F5->g, U+01F8->n, U+01F9->n, U+01FA->a, U+01FB->a, U+0200->a, U+0201->a, U+0202->a, U+0203->a, U+0204->e, U+0205->e, U+0206->e, U+0207->e, U+0208->i, U+0209->i, U+020A->i, U+020B->i, U+020C->o, U+020D->o, U+020E->o, U+020F->o, U+0210->r, U+0211->r, U+0212->r, U+0213->r, U+0214->u, U+0215->u, U+0216->u, U+0217->u, U+0218->s, U+0219->s, U+021A->t, U+021B->t, U+021E->h, U+021F->h, U+0226->a, U+0227->a, U+0228->e, U+0229->e, U+022A->o, U+022B->o, U+022C->o, U+022D->o, U+022E->o, U+022F->o, U+0230->o, U+0231->o, U+0232->y, U+0233->y, U+1E00->a, U+1E01->a, U+1E02->b, U+1E03->b, U+1E04->b, U+1E05->b, U+1E06->b, U+1E07->b, U+1E08->c, U+1E09->c, U+1E0A->d, U+1E0B->d, U+1E0C->d, U+1E0D->d, U+1E0E->d, U+1E0F->d, U+1E10->d, U+1E11->d, U+1E12->d, U+1E13->d, U+1E14->e, U+1E15->e, U+1E16->e, U+1E17->e, U+1E18->e, U+1E19->e, U+1E1A->e, U+1E1B->e, U+1E1C->e, U+1E1D->e, U+1E1E->f, U+1E1F->f, U+1E20->g, U+1E21->g, U+1E22->h, U+1E23->h, U+1E24->h, U+1E25->h, U+1E26->h, U+1E27->h, U+1E28->h, U+1E29->h, U+1E2A->h, U+1E2B->h, U+1E2C->i, U+1E2D->i, U+1E2E->i, U+1E2F->i, U+1E30->k, U+1E31->k, U+1E32->k, U+1E33->k, U+1E34->k, U+1E35->k, U+1E36->l, U+1E37->l, U+1E38->l, U+1E39->l, U+1E3A->l, U+1E3B->l, U+1E3C->l, U+1E3D->l, U+1E3E->m, U+1E3F->m, U+1E40->m, U+1E41->m, U+1E42->m, U+1E43->m, U+1E44->n, U+1E45->n, U+1E46->n, U+1E47->n, U+1E48->n, U+1E49->n, U+1E4A->n, U+1E4B->n, U+1E4C->o, U+1E4D->o, U+1E4E->o, U+1E4F->o, U+1E50->o, U+1E51->o, U+1E52->o, U+1E53->o, U+1E54->p, U+1E55->p, U+1E56->p, U+1E57->p, U+1E58->r, U+1E59->r, U+1E5A->r, U+1E5B->r, U+1E5C->r, U+1E5D->r, U+1E5E->r, U+1E5F->r, U+1E60->s, U+1E61->s, U+1E62->s, U+1E63->s, U+1E64->s, U+1E65->s, U+1E66->s, U+1E67->s, U+1E68->s, U+1E69->s, U+1E6A->t, U+1E6B->t, U+1E6C->t, U+1E6D->t, U+1E6E->t, U+1E6F->t, U+1E70->t, U+1E71->t, U+1E72->u, U+1E73->u, U+1E74->u, U+1E75->u, U+1E76->u, U+1E77->u, U+1E78->u, U+1E79->u, U+1E7A->u, U+1E7B->u, U+1E7C->v, U+1E7D->v, U+1E7E->v, U+1E7F->v, U+1E80->w, U+1E81->w, U+1E82->w, U+1E83->w, U+1E84->w, U+1E85->w, U+1E86->w, U+1E87->w, U+1E88->w, U+1E89->w, U+1E8A->x, U+1E8B->x, U+1E8C->x, U+1E8D->x, U+1E8E->y, U+1E8F->y, U+1E96->h, U+1E97->t, U+1E98->w, U+1E99->y, U+1EA0->a, U+1EA1->a, U+1EA2->a, U+1EA3->a, U+1EA4->a, U+1EA5->a, U+1EA6->a, U+1EA7->a, U+1EA8->a, U+1EA9->a, U+1EAA->a, U+1EAB->a, U+1EAC->a, U+1EAD->a, U+1EAE->a, U+1EAF->a, U+1EB0->a, U+1EB1->a, U+1EB2->a, U+1EB3->a, U+1EB4->a, U+1EB5->a, U+1EB6->a, U+1EB7->a, U+1EB8->e, U+1EB9->e, U+1EBA->e, U+1EBB->e, U+1EBC->e, U+1EBD->e, U+1EBE->e, U+1EBF->e, U+1EC0->e, U+1EC1->e, U+1EC2->e, U+1EC3->e, U+1EC4->e, U+1EC5->e, U+1EC6->e, U+1EC7->e, U+1EC8->i, U+1EC9->i, U+1ECA->i, U+1ECB->i, U+1ECC->o, U+1ECD->o, U+1ECE->o, U+1ECF->o, U+1ED0->o, U+1ED1->o, U+1ED2->o, U+1ED3->o, U+1ED4->o, U+1ED5->o, U+1ED6->o, U+1ED7->o, U+1ED8->o, U+1ED9->o, U+1EDA->o, U+1EDB->o, U+1EDC->o, U+1EDD->o, U+1EDE->o, U+1EDF->o, U+1EE0->o, U+1EE1->o, U+1EE2->o, U+1EE3->o, U+1EE4->u, U+1EE5->u, U+1EE6->u, U+1EE7->u, U+1EE8->u, U+1EE9->u, U+1EEA->u, U+1EEB->u, U+1EEC->u, U+1EED->u, U+1EEE->u, U+1EEF->u, U+1EF0->u, U+1EF1->u, U+1EF2->y, U+1EF3->y, U+1EF4->y, U+1EF5->y, U+1EF6->y, U+1EF7->y, U+1EF8->y, U+1EF9->y 102 | min_infix_len = 2 103 | html_strip = 1 104 | source = group_core_0 105 | } 106 | -------------------------------------------------------------------------------- /.docker/waitfortcp: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | HOST=$1 4 | PORT=$2 5 | 6 | while ! (echo >"/dev/tcp/$HOST/$PORT") &>/dev/null; do 7 | echo "💤 Waiting for $HOST:$PORT to become available." 8 | sleep 1 9 | done 10 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | **/.dockerignore 2 | **/Dockerfile 3 | **/docker-compose.yml 4 | **/.git 5 | **/.gitignore 6 | **/.editorconfig 7 | **/.code-workspace 8 | **/.project 9 | **/.travis.yml 10 | **/AUTHORS 11 | **/CHANGELOG.md 12 | **/README.md 13 | **/COPYING 14 | **/GNU-AGPL-3.0 15 | **/Procfile 16 | **/.s2i 17 | **/.tx 18 | **/log 19 | **/tmp 20 | **/.bundle 21 | **/*.sqlite3 22 | **/*.sqlite3-journal 23 | **/db/sphinx 24 | **/public/uploads 25 | **/node_modules 26 | **/doc 27 | **/.ruby-version 28 | **/.rvm 29 | **/*.env 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | hitobito 2 | hitobito_* 3 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ruby:2.5 as base 2 | 3 | RUN apt-get update && apt-get install -y \ 4 | graphviz \ 5 | imagemagick \ 6 | && rm -rf /var/lib/apt/lists/* 7 | 8 | WORKDIR /app/hitobito/ 9 | COPY hitobito/Wagonfile.ci ./Wagonfile 10 | COPY hitobito/Gemfile hitobito/Gemfile.lock ./ 11 | RUN bundle install 12 | 13 | WORKDIR /app/ 14 | COPY ./ ./ 15 | 16 | RUN ln -s /app/.docker/entrypoint /bin/entrypoint; \ 17 | ln -s /app/.docker/waitfortcp /bin/waitfortcp 18 | 19 | WORKDIR /app/hitobito/ 20 | RUN bundle install 21 | 22 | #################################################################### 23 | FROM base as dev 24 | 25 | ENV RAILS_ENV=development 26 | 27 | ENTRYPOINT [ "/bin/entrypoint" ] 28 | CMD [ "rails", "server", "-b", "0.0.0.0" ] 29 | 30 | #################################################################### 31 | FROM base as test 32 | 33 | ENV RAILS_ENV=test 34 | 35 | ENTRYPOINT [ "/bin/entrypoint" ] 36 | CMD [ "rspec" ] 37 | 38 | #################################################################### 39 | FROM ruby:2.6-alpine3.9 as prod 40 | 41 | WORKDIR /app/hitobito 42 | COPY hitobito/Gemfile hitobito/Gemfile.lock ./ 43 | RUN bundle install \ 44 | --deployment \ 45 | --frozen \ 46 | --without=test \ 47 | --without=development \ 48 | --without=concolse \ 49 | --without=metrics 50 | 51 | COPY .docker/entrypoint .docker/waitfortcp /bin/ 52 | 53 | COPY hitobito/ ./ 54 | 55 | ENV RAILS_ENV=production 56 | 57 | ENTRYPOINT [ "bundle", "exec" ] 58 | CMD [ "rails", "serve" ] 59 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hitobito 2 | 3 | _Hitobito_ is an open source web application to manage complex group hierarchies with members, events and a lot more. 4 | A quick way to begin working on Hitobito and it's wagons is using _Docker_ and _docker-compose_. 5 | 6 | ## System Requirements 7 | 8 | In order to use this method, you need to have [Docker][docker] and _[docker-compose][doco]_ installed on your computer. 9 | The free _Docker Community Edition (CE)_ works perfectly fine. 10 | 11 | [docker]: https://docs.docker.com/install/ 12 | [doco]: https://docs.docker.com/compose/install/ 13 | 14 | ## Preparation 15 | 16 | First, you need to clone this repository: 17 | 18 | ```bash 19 | git clone https://github.com/nxt-engineering/hitobito-docker.git hitobito \ 20 | && cd hitobito 21 | ``` 22 | 23 | This contains only the Docker instructions. 24 | But you will also need the Hitobito source code. 25 | That's why you need to clone the Hitobito core project and the specific Hitobito wagon you'd like to work on: 26 | 27 | ```bash 28 | # core project 29 | git clone https://github.com/hitobito/hitobito.git 30 | 31 | # wagon project(s) 32 | git clone https://github.com/hitobito/hitobito_generic.git 33 | ``` 34 | 35 | You need to set up at least one wagon project. Don't forget to [copy the Wagonfile](https://github.com/hitobito/hitobito/blob/master/doc/development/04_wagons.md#grundlegendes) in the core project! 36 | The final structure should look something like this: 37 | 38 | ```bash 39 | $ ls -lh 40 | total 16K 41 | -rw-r--r-- 1 user 1.3K Jul 15 10:57 Dockerfile 42 | -rw-r--r-- 1 user 1.4K Jul 15 17:43 README.md 43 | -rw-r--r-- 1 user 625 Jul 15 17:41 docker-compose.yml 44 | drwxr-xr-x 36 user 1.2K Jul 15 13:56 hitobito 45 | drwxr-xr-x 27 user 864 Jun 11 09:30 hitobito_generic 46 | ``` 47 | 48 | ## Docker Runtime 49 | 50 | To start the Hitobito application, run the following commands in your shell: 51 | 52 | ```bash 53 | # Start the application 54 | docker-compose up app 55 | 56 | # Open the app: 57 | echo "http://$(docker-compose port app 3000)" 58 | 59 | # In order to "receive" emails, open mailcatcher: 60 | echo "http://$(docker-compose port mail 1080)" 61 | ``` 62 | 63 | It will initially take a while to prepare the initial Docker images, to prepare the database and to start the application. 64 | The process will be shorter on subsequent starts. 65 | 66 | ## First Login 67 | 68 | Get the login information via the Rails console. 69 | 70 | ```bash 71 | echo 'p=Person.first; p.update(password: "password"); "You can now login as #{p.email} with the password \"password\""' | \ 72 | docker-compose run --rm -T app rails c 73 | ``` 74 | 75 | Now you should be able to log-in with the email address in the output and the password _password_. 76 | 77 | ## Debug 78 | 79 | The Rails console is your friend. 80 | Run the following command, to open it. 81 | 82 | ```bash 83 | docker-compose exec app rails c 84 | ``` 85 | 86 | ## Test 87 | 88 | The hitobito application has a lot of rspec tests. 89 | To run them all, use the following command: 90 | 91 | ```bash 92 | docker-compose run --rm test 93 | ``` 94 | 95 | ### Test of a specific Wagon 96 | 97 | To test a specific wagon, you need to cd to the directory. 98 | But because the `entrypoint` script automatically does a `bundle exec` for you (which is fine most of the time), you need to overwrite the entrypoint to be plain `bash`. 99 | 100 | ```bash 101 | $ docker-compose run --rm --entrypoint bash test 102 | Starting hitobito_db-test_1 ... done 103 | root@a42b42c42d42:/app/hitobito# rake db:migrate wagon:migrate # if you changed the db schema 104 | root@a42b42c42d42:/app/hitobito# cd ../hitobito_WAGON/ 105 | root@a42b42c42d42:/app/hitobito_WAGON# rspec 106 | ``` 107 | 108 | ## Seed 109 | 110 | If you need to re-seed your db, use the following command: 111 | 112 | ``` 113 | docker-compose run --rm app rake db:seed wagon:seed 114 | ``` 115 | 116 | ## Full-text search 117 | 118 | Hitobito relies on Sphinx Search for indexing Persons, Events and Groups. 119 | 120 | At first, you need to create the initial index: 121 | 122 | ```bash 123 | docker-compose run --rm indexer 124 | ``` 125 | 126 | Then you can start the Sphinx server: 127 | 128 | ```bash 129 | docker-compose up sphinx 130 | ``` 131 | 132 | The server does not automatically re-index. 133 | In order to re-index, run the indexer again. 134 | 135 | ## Clean up / Reset 136 | 137 | Once you've made your changes and decide to stop working on the project, you should clean up. The following command will remove all data that was created by Docker and _docker-compose_. 138 | 139 | ```bash 140 | docker-compose down --volumes --remove-orphans --rmi local 141 | ``` 142 | 143 | This method is also not too bad if your working environment got screwed up somehow and you'd like to try a fresh start. 144 | 145 | ## Internals 146 | 147 | Here follows a dicussion about why certain things were done a certain way in this repository. 148 | 149 | ### Exposed Ports 150 | 151 | The `docker-compose.yml` file does expose all relevant ports. 152 | But it does not assign them a well-known port. 153 | This means, that it is _intentionally_ not possible to access the main application using `http://localhost:3000`! 154 | Either you use `docker-compose ps` (or the `docker-compose port SERVICE PORTNUMBER` command) to get the actual port Docker assigned – or you use something like [Reception](https://github.com/nxt-engineering/reception). 155 | 156 | Why would you need this _Reception_ thingy? Because it makes all the services accessible through a reverse proxy that is accessible using `http://SERVICENAME.PROJECTNAME.docker` (or `http://SERVICENAME.PROJECTNAME.local` on Linux). 157 | This makes work more convenient and allows to have multiple projects, that all bind to the same port (e.g. `3000`), running at the same time. 158 | (Because Docker will handle the port conflict for us.) 159 | As an extra you get an overview over all running services and their exposed ports for free at `http://reception.docker` (or `http://reception.local` on linux). 160 | 161 | ### Mounts 162 | 163 | The current directy is mounted by _docker-compose_ into the running containers. 164 | The main advantage is a much simpler workflow, because it allows you to change your 'local' files and they are immediately picked up by the commands in the server. 165 | I.e. you don't have to re-build the Docker images after every time. 166 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.4' 2 | services: 3 | app: &app 4 | build: 5 | context: . 6 | target: dev 7 | depends_on: 8 | - db 9 | - mail 10 | - cache 11 | env_file: .docker/app.env 12 | ports: 13 | - 3000 14 | volumes: 15 | - ./:/app 16 | - seed:/seed 17 | 18 | worker: 19 | <<: *app 20 | command: [ rake, 'jobs:work' ] 21 | depends_on: 22 | - db 23 | - mail 24 | - cache 25 | 26 | test: 27 | build: 28 | context: . 29 | target: test 30 | depends_on: 31 | - db-test 32 | env_file: .docker/app.env 33 | environment: 34 | RAILS_DB_NAME: hitobito_test 35 | RAILS_DB_HOST: db-test 36 | volumes: 37 | - ./:/app 38 | 39 | # Dependencies 40 | 41 | mail: 42 | build: 43 | context: . 44 | target: base 45 | command: [ mailcatcher, -f, --ip, '0.0.0.0' ] 46 | ports: 47 | - 1080 48 | 49 | cache: 50 | image: memcached:1.5-alpine 51 | command: [ memcached, -l, '0.0.0.0', -p, '11211' ] 52 | 53 | sphinx: 54 | image: macbre/sphinxsearch:3.1.1 55 | depends_on: 56 | - db 57 | volumes: 58 | - sphinx:/opt/sphinx/index 59 | - ./.docker/sphinx.conf:/opt/sphinx/conf/sphinx.conf:ro 60 | 61 | indexer: 62 | image: macbre/sphinxsearch:3.1.1 63 | command: [ indexer, --config, /opt/sphinx/conf/sphinx.conf, --all ] 64 | depends_on: 65 | - db 66 | volumes: 67 | - sphinx:/opt/sphinx/index 68 | - ./.docker/sphinx.conf:/opt/sphinx/conf/sphinx.conf:ro 69 | 70 | db: 71 | image: mysql:5.6 72 | command: 73 | - --sort_buffer_size=2M 74 | env_file: .docker/mysql.env 75 | volumes: 76 | - db:/var/lib/mysql 77 | 78 | db-test: 79 | image: mysql:5.6 80 | command: 81 | - --sort_buffer_size=2M 82 | env_file: .docker/mysql.env 83 | environment: 84 | MYSQL_DATABASE: hitobito_test 85 | 86 | volumes: 87 | db: 88 | sphinx: 89 | seed: 90 | 91 | --------------------------------------------------------------------------------