status-im / infra-office-legacy

Infrastructure for cloud office services
0 stars 0 forks source link

Deploy CRM platform for Ambassador Program #8

Closed jakubgs closed 2 years ago

jakubgs commented 3 years ago

@jinhojang6 requested a deployment of a CRM paltform so he can manage the ambassador program.

The current options:

Preferred domain: https://admin-ambassador.status.im/

jakubgs commented 3 years ago

A Dockerfile and an example Docker Compose setup exist: https://github.com/Bottelet/DaybydayCRM/blob/master/Dockerfile https://github.com/Bottelet/DaybydayCRM/blob/master/docker-compose.yml

It appears on of the dependencies is an ElasticSearch cluster: https://github.com/Bottelet/DaybydayCRM/blob/master/docker-compose.yml#L83-L118

jakubgs commented 2 years ago

I managed to get the Docker image build going but had to update the Dockerfile a bit:

diff --git a/Dockerfile b/Dockerfile
index 702ca5b..11a03bf 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -16,8 +16,8 @@ RUN apt-get update && \
     cron \
     nginx \
     nano \
-    python \
-    python-pip \
+    python3 \
+    python3-pip \
     && pecl channel-update pecl.php.net \
     && pecl install apcu \
     && pip install awscli

I also had to copy .docker/nginx/nginx-local.conf as .docker/nginx/nginx.conf to provide basic Nginx config.

jakubgs commented 2 years ago

Looks like their Dockerfile tries to install very old NodeJS which is not supported on bullseye:

## Confirming "bullseye" is supported...

+ curl -sLf -o /dev/null 'https://deb.nodesource.com/node_11.x/dists/bullseye/Release'

## Your distribution, identified as "bullseye", is not currently supported, please contact NodeSource at https://github.com/nodesource/distributions/issues if you think this is incorrect or would like your distribution to be considered for support

The command '/bin/sh -c curl -sL https://deb.nodesource.com/setup_11.x | bash -' returned a non-zero code: 1
jakubgs commented 2 years ago

The build process fails for some weird reasons:

<s> [webpack.Progress] 95% emitting
<s> [webpack.Progress] 95% emitting unnamed compat plugin
node:fs:585
  handleErrorFromBinding(ctx);
  ^

Error: EACCES: permission denied, open '/var/www/html/public/mix-manifest.json'
    at Object.openSync (node:fs:585:3)
    at Object.writeFileSync (node:fs:2153:35)
    at File.write (/var/www/html/node_modules/laravel-mix/src/File.js:157:12)
    at Manifest.refresh (/var/www/html/node_modules/laravel-mix/src/Manifest.js:78:14)
    at /var/www/html/node_modules/laravel-mix/src/webpackPlugins/ManifestPlugin.js:12:43
    at AsyncSeriesHook.eval [as callAsync] (eval at create (/var/www/html/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:28:1)
    at AsyncSeriesHook.lazyCompileHook (/var/www/html/node_modules/tapable/lib/Hook.js:154:20)
    at Compiler.emitAssets (/var/www/html/node_modules/webpack/lib/Compiler.js:491:19)
    at onCompiled (/var/www/html/node_modules/webpack/lib/Compiler.js:278:9)
    at /var/www/html/node_modules/webpack/lib/Compiler.js:681:15
    at AsyncSeriesHook.eval [as callAsync] (eval at create (/var/www/html/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:6:1)
    at AsyncSeriesHook.lazyCompileHook (/var/www/html/node_modules/tapable/lib/Hook.js:154:20)
    at /var/www/html/node_modules/webpack/lib/Compiler.js:678:31
    at AsyncSeriesHook.eval [as callAsync] (eval at create (/var/www/html/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:9:1)
    at AsyncSeriesHook.lazyCompileHook (/var/www/html/node_modules/tapable/lib/Hook.js:154:20)
    at /var/www/html/node_modules/webpack/lib/Compilation.js:1423:35
    at AsyncSeriesHook.eval [as callAsync] (eval at create (/var/www/html/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:9:1)
    at AsyncSeriesHook.lazyCompileHook (/var/www/html/node_modules/tapable/lib/Hook.js:154:20)
    at /var/www/html/node_modules/webpack/lib/Compilation.js:1414:32
    at eval (eval at create (/var/www/html/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:19:1)
    at processTicksAndRejections (node:internal/process/task_queues:96:5) {
  errno: -13,
  syscall: 'open',
  code: 'EACCES',
  path: '/var/www/html/public/mix-manifest.json'
}
jakubgs commented 2 years ago

For some unknown reason Node 16 causes the EACCES: permission denied, downgrading to 14 fixes it:

 > docker build -t statusteam/daybyday-crm:2.2.0 .
...
Successfully built bf8a67ad8dd0
Successfully tagged statusteam/daybyday-crm:2.2.0
diff --git a/Dockerfile b/Dockerfile
index 702ca5b..9c8fc77 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -16,8 +16,8 @@ RUN apt-get update && \
     cron \
     nginx \
     nano \
-    python \
-    python-pip \
+    python3 \
+    python3-pip \
     && pecl channel-update pecl.php.net \
     && pecl install apcu \
     && pip install awscli
@@ -49,7 +49,7 @@ RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local
 COPY .docker/nginx/nginx.conf /etc/nginx/nginx.conf

 #Frotend NPM/YARN
-RUN curl -sL https://deb.nodesource.com/setup_11.x | bash -
+RUN curl -sL https://deb.nodesource.com/setup_14.x | bash -
 RUN apt-get install -y nodejs
 RUN curl -sL https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
 RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
jakubgs commented 2 years ago

It appears that the main Dockerfile tries to combine Nginx and the PHP process into one, while the Docker Compose file requires two other images to be built. If I try to run the former alone I get:

...
> php artisan route:cache
Route cache cleared!
Routes cached successfully!
[07-Dec-2021 19:17:05] NOTICE: Failed implicitly binding to ::, retrying with 0.0.0.0
[07-Dec-2021 19:17:05] NOTICE: Failed implicitly binding to ::, retrying with 0.0.0.0
[07-Dec-2021 19:17:05] NOTICE: fpm is running, pid 235
[07-Dec-2021 19:17:05] NOTICE: ready to handle connections
nginx: [emerg] host not found in upstream "php" in /etc/nginx/nginx.conf:26
jakubgs commented 2 years ago

I have most of the Ansible role done, just getting some kinks out.

jinhojang6 commented 2 years ago

Wow Genius... No rush!

jakubgs commented 2 years ago

Currently I'm seeing some kind of dependency issue with my DayByDay-CRM Docker setup:

Error:
Class 'Laravel\Dusk\DuskServiceProvider' not found

  at /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Application.php:690
...

Stack trace: https://gist.github.com/jakubgs/3b45a87ef5455ce058d2131d630c0cc9

jakubgs commented 2 years ago

The dependency is already listed in composer.json:

        "laravel/dusk": "^5.8",

https://github.com/Bottelet/DaybydayCRM/blob/3c5ed12e217140859ff980161a742f8f58368151/composer.json#L43

But, it appears to be listed in require-dev, not require, so it seems like it's a development-only dependency.

jakubgs commented 2 years ago

And we can see in the Dockerfile that the composer call uses the --no-dev flag:

CMD composer install --no-ansi --no-dev --no-interaction --optimize-autoloader && php-fpm -D && nginx -g "daemon off;"

https://github.com/Bottelet/DaybydayCRM/blob/3c5ed12e217140859ff980161a742f8f58368151/Dockerfile#L78

jakubgs commented 2 years ago

Yep, removing --no-dev from the composer install command fixes it, and I do want that since I'm using APP_DEBUG=true.

jakubgs commented 2 years ago

Looks like migrations need to be ran after installation:

Illuminate\Database\QueryException
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'daybydaycrm.users' doesn't exist (SQL: select * from `users` where `email` = user-login and `users`.`deleted_at` is null limit 1)
jakubgs commented 2 years ago

And indeed, according to their docs I need to run:

docker-compose exec php php artisan migrate --seed

https://github.com/Bottelet/DaybydayCRM/wiki/Install-using-Docker

jakubgs commented 2 years ago

I tried adding call to php artican migrate in the CMD line of Dockefile but it doesn't seem to work:

admin@node-01.do-ams3.crm.office:~ % d exec -it daybyday-crm-db mysql -p                
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 10
Server version: 5.7.36 MySQL Community Server (GPL)

mysql> USE daybydaycrm
Database changed
mysql> SHOW TABLES;
Empty set (0.00 sec)
jakubgs commented 2 years ago

If I run php artisan migrate by hand it clearly works:

admin@node-01.do-ams3.crm.office:~ % d exec -it daybyday-crm-app bash
root@8fe36c3bf82c:/var/www/html# php artisan migrate
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated:  2014_10_12_000000_create_users_table (0.13 seconds)
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated:  2014_10_12_100000_create_password_resets_table (0.02 seconds)
...
Migrating: 2021_03_02_132033_alter_comments_table_add_long_text
Migrated:  2021_03_02_132033_alter_comments_table_add_long_text (0.02 seconds)
root@8fe36c3bf82c:/var/www/html# 
exit

admin@node-01.do-ams3.crm.office:~ % d exec -it daybyday-crm-db mysql -p                
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 13
Server version: 5.7.36 MySQL Community Server (GPL)

mysql> USE daybydaycrm
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> SHOW TABLES;
+-----------------------+
| Tables_in_daybydaycrm |
+-----------------------+
| absences              |
...
| users                 |
+-----------------------+
32 rows in set (0.00 sec)
jakubgs commented 2 years ago

I don't know if I like what I see when I try to login into DayByDayCRM:

image

jakubgs commented 2 years ago

I can create the first admin user by using the default seed data:

admin@node-01.do-ams3.crm.office:~ % d exec -it daybyday-crm-app bash
root@8fe36c3bf82c:/var/www/html# php artisan db:seed
Seeding: StatusTableSeeder
Seeded:  StatusTableSeeder (0.12 seconds)
Seeding: UsersTableSeeder
Seeded:  UsersTableSeeder (0.18 seconds)
Seeding: IndustriesTableSeeder
Seeded:  IndustriesTableSeeder (0 seconds)
Seeding: DepartmentsTableSeeder
Seeded:  DepartmentsTableSeeder (0.01 seconds)
Seeding: SettingsTableSeeder
Seeded:  SettingsTableSeeder (0.02 seconds)
Seeding: PermissionsTableSeeder
Seeded:  PermissionsTableSeeder (0.07 seconds)
Seeding: RolesTablesSeeder
Seeded:  RolesTablesSeeder (0.02 seconds)
Seeding: RolePermissionTableSeeder
Seeded:  RolePermissionTableSeeder (0.12 seconds)
Seeding: UserRoleTableSeeder
Seeded:  UserRoleTableSeeder (0 seconds)

But that creates a bunch of other stuff, also the user credentials are default and public.

mysql> SELECT name,email FROM users;
+-------+-----------------+
| name  | email           |
+-------+-----------------+
| Admin | admin@admin.com |
+-------+-----------------+
1 row in set (0.00 sec)
jakubgs commented 2 years ago

One can create a user programmatically using php artisan tinker:

admin@node-01.do-ams3.crm.office:~ % d exec -it daybyday-crm-app bash   
root@8fe36c3bf82c:/var/www/html# php artisan tinker
Psy Shell v0.10.4 (PHP 7.3.33 — cli) by Justin Hileman
>>> DB::table('users')->insert(['name'=>'Jakub','email'=>'jakub@status.im','password'=>Hash::make('...')])
=> true
mysql> SELECT name,email FROM users;
+------------+--------------------+
| name       | email              |
+------------+--------------------+
| Admin      | admin@admin.com    |
| Jakub      | jakub@status.im    |
+------------+--------------------+
2 rows in set (0.00 sec)

https://stackoverflow.com/a/35754495

But apparently a more kosher way is using the database seeder: https://laravel.com/docs/5.2/seeding

jakubgs commented 2 years ago

This is a new one:

UnexpectedValueException
The stream or file "/var/www/html/storage/logs/laravel.log" could not be opened in append mode: failed to open stream: Permission denied
jakubgs commented 2 years ago

I can see the line that adjusts permissions for the storage folder in the Dockerfile:

# Set permissions
RUN chmod 0777 ./bootstrap/cache -R
RUN chmod 0777 ./storage/* -R

https://github.com/Bottelet/DaybydayCRM/blob/830b3c52475441ea9dd619ac7630722299293cad/Dockerfile#L70-L72

So they must be changed at runtime:

admin@node-01.do-ams3.crm.office:/docker/daybyday-crm % d exec -it daybyday-crm-app bash
root@6fc8932380cb:/var/www/html# ls -l | grep storage
drwxr-xr-x  1 root     root       4096 Nov 30 17:51 storage
jakubgs commented 2 years ago

Or not... because the image has it already at 0755:

 > d run -it --entrypoint /bin/bash statusteam/daybyday-crm:2.2.0
root@fbbf29130bd8:/var/www/html# ls -l | grep storage
drwxr-xr-x   5 root     root       4096 Nov 30 17:51 storage
jakubgs commented 2 years ago

Oh wait, I see it, it's the file itself that has wrong permissions:

root@6fc8932380cb:/var/www/html# ls -l storage/logs
total 80
-rw-r--r-- 1 root root 76482 Jan 18 19:22 laravel.log

Which is most probably caused by running php artisan migrate as part of container CMD and as root.

jakubgs commented 2 years ago

And indeed, the file is missing from the clean image:

 > d run -it --entrypoint /bin/bash statusteam/daybyday-crm:2.2.0
root@127495519cdd:/var/www/html# ls -l storage/logs
total 0
root@127495519cdd:/var/www/html# 
jakubgs commented 2 years ago

I should probably split the container into two containers running an Nginx proxy and a php-fpm process.

jakubgs commented 2 years ago

Looks like I need something to wait for the DB initialization, because the migration can fail with:

SQLSTATE[HY000] [2002] Connection refused (SQL: select * from information_schema.tables where table_schema = daybydaycrm and table_name = migrations and table_type = 'BASE TABLE')

Adding a healhcheck to the MySQL docker container should allow Docker Compose to wait for it to be healthy.

jakubgs commented 2 years ago

Another new one:

ErrorException
Trying to get property 'country' of non-object

Looks like seeding might be necessary to make this run.

jakubgs commented 2 years ago

If I do the seeding I get yet another issue:

ErrorException
Trying to get property 'name' of non-object (View: /var/www/html/resources/views/navigation/topbar/user-profile.blade.php)

This is getting tiresome.

jakubgs commented 2 years ago

And we have a problem with mixed transport:

image

jakubgs commented 2 years ago

Changes:

Still needs some work.

jakubgs commented 2 years ago

We can see that asset URLs are generated using the URL::asset() function from Laravel:

    <link href="{{ URL::asset('css/jasny-bootstrap.css') }}" rel="stylesheet" type="text/css">
    <link href="{{ URL::asset('css/font-awesome.min.css') }}" rel="stylesheet" type="text/css">
    <link href="{{ URL::asset('css/dropzone.css') }}" rel="stylesheet" type="text/css">

https://github.com/Bottelet/DaybydayCRM/blob/830b3c52/resources/views/layouts/master.blade.php#L6-L8

And according to these posts this can be adjusted using APP_URL, APP_URI, or ASSET_URL: https://stackoverflow.com/questions/47018712/mixed-content-laravel/51252531 https://laracasts.com/discuss/channels/laravel/mixed-content-issue-content-must-be-served-as-https

But I've tried all three and none worked.

jakubgs commented 2 years ago

We can see they reference use of APP_URL in their example docker-compose.env:

APP_URL=http://nginx

https://github.com/Bottelet/DaybydayCRM/blob/d1965973f60933fd293aaaaa9f71e9d27edfd819/docker-compose.env#L4

And we see it referenced in application config:

    /*
    |--------------------------------------------------------------------------
    | Application URL
    |--------------------------------------------------------------------------
    |
    | This URL is used by the console to properly generate URLs when using
    | the Artisan command line tool. You should set this to the root of
    | your application so that it is used when running Artisan tasks.
    |
    */

    'url' => env('APP_URL', 'http://localhost'),

https://github.com/Bottelet/DaybydayCRM/blob/3c5ed12e217140859ff980161a742f8f58368151/config/app.php

So I'm not sure what's up.

jakubgs commented 2 years ago

I've created an issue about the mixed content errors: https://github.com/Bottelet/DaybydayCRM/issues/287

jakubgs commented 2 years ago

And created another issue about creating the admin user: https://github.com/Bottelet/DaybydayCRM/issues/288

jakubgs commented 2 years ago

I've managed to fix the mixed content errors by adding this line:

    'asset_url' => env('ASSET_URL', null),

https://github.com/laravel/laravel/blob/7.x/config/app.php#L57

To the config/app.php config file. I can modify Dockerfile to do that, but it is weird it's missing.

jakubgs commented 2 years ago

Some changes I applied today:

Still need to figure out how I want to apply the fix to the config/app.php. I might just do my own Dockerfile.

jakubgs commented 2 years ago

Still getting "mixed content" errors from console when trying to create users or projects:

image

So adding the asset_url line only fixed asset links.

jakubgs commented 2 years ago

Some suggestions include adding a URL::forceScheme('https'); line to some files:

Not a fan of having to change the code just to deploy an application in production.

jakubgs commented 2 years ago

And indeed, adding the line does work:

diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php
index 4eb697f..a07d697 100644
--- a/app/Providers/AppServiceProvider.php
+++ b/app/Providers/AppServiceProvider.php
@@ -15,6 +15,7 @@ use App\Observers\ProjectObserver;
 use App\Observers\InvoiceObserver;
 use App\Repositories\Format\GetDateFormat;
 use Illuminate\Support\ServiceProvider;
+use Illuminate\Support\Facades\URL;
 use Laravel\Dusk\DuskServiceProvider;
 use Laravel\Cashier\Cashier;

@@ -27,6 +28,9 @@ class AppServiceProvider extends ServiceProvider
      */
     public function boot()
     {
+        if ($this->app->environment('production')) {
+            URL::forceScheme('https');
+        }
         Cashier::ignoreMigrations();
         Client::observe(ClientObserver::class);
         Task::observe(TaskObserver::class);

But I really don't like having to change code just to run it.

jakubgs commented 2 years ago

This is an issue worth noting:

ERROR: [1] bootstrap checks failed
[1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

ES node is very memory hungry.

jakubgs commented 2 years ago

Changes:

Last step is to give access to Jinho.

jakubgs commented 2 years ago

I've created an account for Jinho. For now I consider this done.