モニカCRMはECS、S 3、SESとオーロラを使用して低コストのドッキング配備でAWSに行きます

57125 ワード

なぜこのプロジェクト?


私は数ヶ月前モニカCRMを発見し、私はこのツールの大ファンです.私は最近、多くの新しい知人を作っていますが、私は常にそれが圧倒的に私はすでに既存の関係の育成に苦労して知っている.
モニカCRMは、そのシンプルさのために完璧な答えだったが、それは私がすぐに私は私の連絡先を持っている議論についていくつかのメモをログに記録することができます.先月、誰かが昆虫養殖プロジェクトについて話してくれたことを覚えているのであれば、誰も覚えていない.私は、彼らはまた、ビジネスの連絡先でない限り、個人的な関係のためにそれを使用していません.私たちが「友人」や「家族」だけなら、私はあなたにファイルを持っていません.
私は連絡先の詳細を検索できるように小さなハックを行う必要がありました.私は、このポストの後でそれをカバーします.
モニカを使用するためのさまざまなオプションがあります.
  • Sanasとしてモニカによって提供されるオンライン版を使用してください.無料版は10連絡先に制限されています-あなたが少し離れて社会的な距離を取っていない限り、テストを超えて使用不可.支払われた1つは制限なしで、1年前に支払われるならば、$ 9/月または7.50/monthのために提供されます.
  • 自分自身をインストールします.プロジェクトは完全にオープンソースであり、Dockerを使用するなどのさまざまな方法があります.
  • 私がAWSに少し執着しているので、それは私のための自然な選択でした.それは良いタイミングでもありました.なぜなら、私は実際にドッカーについてもっと学び、私の手を汚すために良いユースケースを見つけるための時間であると決めました.
    私はgithub、dockerhubとウェブ上のすべてを見たが、AWSの上でモニカを走らせることについてのどんなポストも見つけることができませんでした.私の目的は、低コストで管理されたAWSサービスをできるだけ信頼することでした.私も将来のAWSトレーニングのための代入としてこの例を使いたいです.
    私の展開の毎月のコストは以下の通りです.
  • EC 2 T 3 Aマクロ:1$/月(予約済みのインスタンスとして前払い)
  • EBS磁気30 GB:1.50 $/(無料の層を使用するならば、無料でさえありえます)
  • MySQLオーロラ:1ドル/月未満(私は平均で1日2回モニカを使用しています)
  • S 3とSES : $ 0近く(無視可能)
  • 総費用:3.50ドル/月(無料層に基づいている場合は以下)
    しかしながら、ECSに使用されるEC 2インスタンスは、このプロジェクトに使用されるコンテナをホストするだけです.EC 2およびEBSコストは、他の小さなコンテナを同じインスタンスで実行する場合、他のプロジェクトと共有されます.

    ビルのブロックは何ですか。


    プロジェクトは2つのDockerコンテナを使用します.
  • モニカCRMアプリ(標準モニカ容器)
  • SPELエンドポイントとしてのtraefikリバースプロキシ
  • 私はNginxの代わりにtraefikを好奇心から使用しました.それは非常により若いプロジェクトです、しかし、私はそれがマイクロサービスと容器建築のために大きな逆代理人として人気を集めていると聞きました.SSL証明書はTheefikによって暗号化されます(コンテナのブートストラップであらかじめ設定されます).
    EC 2で動くECSは、Dockerコンテナを管理するのに用いられます.
    それがServerlessオーロラサービスとして構成されるので、MySQLはコンテナとして含まれません.
    この例では、パブリックエンドネットを使用して、コンテナをホストしているインスタンスとMySQLのエンドポイント用のプライベートサブネットのVPCを使用します.

    必要条件


    パブリックドメインが必要です.
    また、モニカが通知などの電子メール情報を送信するために使用されるSMTP資格情報のセットが必要です.これらはAWS SESサービスを使用して作成できます.
    すべての他のコンポーネントは、このチュートリアルに従って作成されます.

    関連AWSユーザーでS 3バケツをつくってください


    このバケットは、あなたの連絡先のアバターやプロフィールの写真などのアップロードされたファイルを保存するモニカによって使用されます.
    バケットが作成されると、モニカがバケットにアクセスするために使用される特定のユーザーを設定します.必要なS 3権限を割り当て、S 3ポリシーを作成することを忘れないでください.
    レコードの完全なS 3の名前だけでなく、新しいユーザーのキーと秘密.次のステップで必要です.
    IAM特権
    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Sid": "VisualEditor0",
                "Effect": "Allow",
                "Action": [
                    "s3:GetObjectRetention",
                    "s3:DeleteObjectVersion",
                    "s3:GetObjectVersionTagging",
                    "s3:ListBucket",
                    "s3:PutObjectLegalHold",
                    "s3:ReplicateObject",
                    "s3:GetBucketObjectLockConfiguration",
                    "s3:PutObject",
                    "s3:GetObjectAcl",
                    "s3:GetObject",
                    "s3:PutObjectRetention",
                    "s3:GetObjectVersionAcl",
                    "s3:GetObjectTagging",
                    "s3:GetObjectVersionForReplication",
                    "s3:DeleteObject",
                    "s3:GetBucketLocation",
                    "s3:GetObjectVersion"
                ],
                "Resource": [
                    "arn:aws:s3:::monicacrmlaurent",
                    "arn:aws:s3:::monicacrmlaurent/*"
                ]
            }
        ]
    }
    
    S 3ポリシー例:
    {
        "Version": "2012-10-17",
        "Id": "Policy1598008770540",
        "Statement": [
            {
                "Sid": "Stmt1598008766523",
                "Effect": "Allow",
                "Principal": {
                    "AWS": "arn:aws:iam::759642557178:user/monicahq"
                },
                "Action": "s3:*",
                "Resource": "arn:aws:s3:::monicacrmlaurent/*"
            }
        ]
    }
    
    我々はおそらくさらに制限を絞り込むことができることに注意してください.

    VPC環境設定


    VPCを作成します.そのウィザードを使用できます.

    将来のMySQLエンドポイントへのアクセスを許可するセキュリティグループを作成します.


    オーロラデータベース


    まず、オーロラエンドポイントのDBサブネットグループを作成する必要があります.この例では、AZは単一のAZでDBサブネットグループを許可しないので、追加のAZで2番目のプライベートサブネットを作成しなければなりませんでした.

    次にオーロラクラスタを作成します.


    Serverlessを選択してください.

    ユーザー名とパスワードを選択します.モニカアプリコンテナーの環境変数として必要になるので、覚えておいてください.

    あなたは容量の設定でコストを制御することができます.この例ではオーロラは1容量単位(2 GB RAM)を超えないようにしています.私が私の個人的なCRMの唯一のユーザーであると考えて、それは十分以上です!
    私は、オーロラクラスタが活動の45分後に一時停止するようにそこで定義しています.

    接続セクションでは、DBサブネットグループ、VPC、サブネット、セキュリティグループを割り当てることができます.


    ECSクラスタの準備(オプション)


    既にECSクラスタがコンテナをホストする準備ができているなら、この部分を飛ばすことができます.ない場合は、次の手順に従って新しいものを作成します.
    まず、新しいECSクラスタを作成します.


    次にEC 2インスタンス型を選択します.私はT 3 Aを選びます.ナノはそれが利用できる最も安いものであり、それは私の2コンテナのために十分以上です.

    SSLを外部から許可するために以前に作成されたセキュリティグループを割り当てます.


    ECSクラスタはEN EC 2インスタンスを自動的に起動します.

    このインスタンスにエラスティックIPを割り当てることもできます.
    もう一つの安価な微調整は、関連するEBSボリュームを磁気に変えます.そして、それはデフォルトのGP 2(SSD)より安いです、そして、個人的なCRMのためにパフォーマンスに関して十分です.既存のインスタンスで変更することができますだけでなく、ECSによって作成された起動設定自動スケーリンググループで.

    コンテナを実行するタスク定義を定義する


    EC 2に基づく新しいタスク定義を作成します.

    次のウィンドウで、JSONファイルを読み込むためにJSON経由でconfigureを選択します.
    ファイルを使用します.JSONと以下のようにマークされたパラメータを変更します.

    <<AWS REGION>> = AWS Region where the containers are running
    <<APP KEY>> = choose a random string that unique for your Monica app
    <<BUCKET NAME>> = Full bucket name
    <<BUCKET REGION>> = Bucket region
    <<AWS KEY TO ACCESS BUCKET>> = Key of the user created for the bucket
    <<AWS SECRET TO ACCESS BUCKET>> = Secret of the user
    <<AURORA CLUSTER NAME>> = Full name of the Aurora cluster
    <<MYSQL USERNAME>> = MySQL username created earlier
    <<MYSQL PASSWORD>> = MySQL password created earlier
    <<FROM EMAIL ADDRESS>> = FROM address used for sending email notifications
    <<FROM EMAIL NAME>> = FROM name used for sending email notifications
    <<SMTP HOST>> = SMTP host obtained from SES
    <<SMTP USERNAME>> = SMTP username obtained from SES
    <<SMTP PASSWORD>> = SMTP password obtained from SES
    <<FQDN OF MONICA CRM>> = Full public name of your Monica app
    <<EMAIL ADDRESS CERTIFICATE REGISTRATION>> = Email used to request a free Let's Encrypt certificate


    タスク定義JSON :
    {
        "ipcMode": null,
        "executionRoleArn": "<create_new>",
        "containerDefinitions": [
            {
                "dnsSearchDomains": null,
                "environmentFiles": [],
                "logConfiguration": {
                    "logDriver": "awslogs",
                    "options": {
                        "awslogs-group": "/ecs/MonicaCRM",
                        "awslogs-region": "<<AWS REGION>>",
                        "awslogs-stream-prefix": "ecs"
                    }
                },
                "entryPoint": [],
                "portMappings": [],
                "command": [],
                "linuxParameters": null,
                "cpu": 0,
                "environment": [
                    {
                        "name": "APP_DISABLE_SIGNUP",
                        "value": "false"
                    },
                    {
                        "name": "APP_KEY",
                        "value": "<<APP KEY>>"
                    },
                    {
                        "name": "APP_TRUSTED_PROXIES",
                        "value": "*"
                    },
                    {
                        "name": "AWS_BUCKET",
                        "value": "<<BUCKET NAME>>"
                    },
                    {
                        "name": "AWS_REGION",
                        "value": "<<BUCKET REGION>>"
                    },
                    {
                        "name": "AWS_KEY",
                        "value": "<<AWS KEY TO ACCESS BUCKET>>"
                    },
                    {
                        "name": "AWS_SECRET",
                        "value": "<<AWS SECRET TO ACCESS BUCKET>>"
                    },
                    {
                        "name": "AWS_SERVER",
                        "value": ""
                    },
                    {
                        "name": "DAV_ENABLED",
                        "value": "true"
                    },
                    {
                        "name": "DB_HOST",
                        "value": "<<AURORA CLUSTER NAME>>"
                    },
                    {
                        "name": "DB_USERNAME",
                        "value": "<<MYSQL USERNAME>>"
                    },
                    {
                        "name": "DB_PASSWORD",
                        "value": "<<MYSQL PASSWORD>>"
                    },
                    {
                        "name": "DEFAULT_FILESYSTEM",
                        "value": "s3"
                    },
                    {
                        "name": "MAIL_ENCRYPTION",
                        "value": "tls"
                    },
                    {
                        "name": "MAIL_FROM_ADDRESS",
                        "value": "<<FROM EMAIL ADDRESS>>"
                    },
                    {
                        "name": "MAIL_FROM_NAME",
                        "value": "<<FROM EMAIL NAME>>"
                    },
                    {
                        "name": "MAIL_HOST",
                        "value": "<<SMTP HOST>>"
                    },
                    {
                        "name": "MAIL_MAILER",
                        "value": "smtp"
                    },
                    {
                        "name": "MAIL_USERNAME",
                        "value": "<<SMTP USERNAME>>"
                    },
                    {
                        "name": "MAIL_PASSWORD",
                        "value": "<<SMTP PASSWORD>>"
                    },
                    {
                        "name": "MAIL_PORT",
                        "value": "587"
                    },
                    {
                        "name": "MFA_ENABLED",
                        "value": "true"
                    }
                ],
                "resourceRequirements": null,
                "ulimits": null,
                "dnsServers": null,
                "mountPoints": null,
                "workingDirectory": null,
                "secrets": null,
                "dockerSecurityOptions": null,
                "memoryReservation": 250,
                "volumesFrom": null,
                "stopTimeout": null,
                "image": "monicahq/monicahq",
                "startTimeout": null,
                "firelensConfiguration": null,
                "dependsOn": null,
                "disableNetworking": null,
                "interactive": null,
                "healthCheck": null,
                "essential": true,
                "links": [],
                "hostname": null,
                "extraHosts": null,
                "pseudoTerminal": null,
                "user": null,
                "readonlyRootFilesystem": null,
                "dockerLabels": {
                    "traefik.enable": "true",
                    "traefik.http.routers.app.entrypoints": "app",
                    "traefik.http.routers.app.rule": "Host(`<<FQDN OF MONICA CRM>>`)",
                    "traefik.http.routers.app.tls.certresolver": "mytls"
                },
                "systemControls": null,
                "privileged": null,
                "name": "app",
                "repositoryCredentials": {
                    "credentialsParameter": ""
                }
            },
            {
                "dnsSearchDomains": null,
                "environmentFiles": [],
                "logConfiguration": {
                    "logDriver": "awslogs",
                    "options": {
                        "awslogs-group": "/ecs/MonicaCRM",
                        "awslogs-region": "<<AWS REGION>>",
                        "awslogs-stream-prefix": "ecs"
                    }
                },
                "entryPoint": null,
                "portMappings": [
                    {
                        "hostPort": 443,
                        "protocol": "tcp",
                        "containerPort": 443
                    },
                    {
                        "hostPort": 8080,
                        "protocol": "tcp",
                        "containerPort": 8080
                    }
                ],
                "command": [],
                "linuxParameters": null,
                "cpu": 0,
                "environment": [
                    {
                        "name": "TRAEFIK_API_INSECURE",
                        "value": "true"
                    },
                    {
                        "name": "TRAEFIK_CERTIFICATESRESOLVERS_MYTLS_ACME_EMAIL",
                        "value": "<<EMAIL ADDRESS CERTIFICATE REGISTRATION>>"
                    },
                    {
                        "name": "TRAEFIK_CERTIFICATESRESOLVERS_MYTLS_ACME_TLSCHALLENGE",
                        "value": "true"
                    },
                    {
                        "name": "TRAEFIK_CERTIFICATESRSOLVERS_MYTLS_ACME_STORAGE",
                        "value": "/letsencrypt/acme.json"
                    },
                    {
                        "name": "TRAEFIK_ENTRYPOINTS_APP_ADDRESS",
                        "value": ":443"
                    },
                    {
                        "name": "TRAEFIK_PROVIDERS_DOCKER",
                        "value": "true"
                    },
                    {
                        "name": "TRAEFIK_PROVIDERS_DOCKER_EXPOSEDBYDEFAULT",
                        "value": "false"
                    }
                ],
                "resourceRequirements": null,
                "ulimits": null,
                "dnsServers": null,
                "mountPoints": [
                    {
                        "readOnly": true,
                        "containerPath": "/var/run/docker.sock",
                        "sourceVolume": "dockersock"
                    },
                    {
                        "readOnly": null,
                        "containerPath": "/letsencrypt",
                        "sourceVolume": "tmp"
                    }
                ],
                "workingDirectory": null,
                "secrets": null,
                "dockerSecurityOptions": null,
                "memoryReservation": 200,
                "volumesFrom": null,
                "stopTimeout": null,
                "image": "traefik:v2.3.0-rc2",
                "startTimeout": null,
                "firelensConfiguration": null,
                "dependsOn": [
                    {
                        "containerName": "app",
                        "condition": "START"
                    }
                ],
                "disableNetworking": null,
                "interactive": null,
                "healthCheck": null,
                "essential": true,
                "links": null,
                "hostname": null,
                "extraHosts": null,
                "pseudoTerminal": null,
                "user": null,
                "readonlyRootFilesystem": null,
                "dockerLabels": null,
                "systemControls": null,
                "privileged": null,
                "name": "traefik",
                "repositoryCredentials": {
                    "credentialsParameter": ""
                }
            }
        ],
        "memory": null,
        "taskRoleArn": "",
        "family": "MonicaCRM",
        "pidMode": null,
        "requiresCompatibilities": [
            "EC2"
        ],
        "networkMode": null,
        "cpu": null,
        "inferenceAccelerators": null,
        "proxyConfiguration": null,
        "volumes": [
            {
                "efsVolumeConfiguration": null,
                "name": "dockersock",
                "host": {
                    "sourcePath": "/var/run/docker.sock"
                },
                "dockerVolumeConfiguration": null
            },
            {
                "efsVolumeConfiguration": null,
                "name": "tmp",
                "host": {
                    "sourcePath": "/tmp/"
                },
                "dockerVolumeConfiguration": null
            }
        ],
        "placementConstraints": [],
        "tags": []
    }
    
    タスク定義が作成されると、タスクを実行してコンテナを起動します.

    タスクが実行していることを確認します.

    パブリックドメインの設定


    この時点で、あなたは、あなたの公開DNSの中にMonicaが走っているEC 2インスタンスのIPアドレスを示すAレコードを加えるべきです.私の例では、次のエントリを記録します.
    CRMMyDomainコム

    完了!


    今、あなたはそのDNSレコードCRMを使用してHTTPS経由でモニカCRMにアクセスする必要があります.MyDomainCOM .

    つの小さなトリックあなたの連絡先をより検索できるようにする


    私は、我々がモニカの検索バーですべての連絡先詳細を捜すことができないことを非常に制限します.たとえば、会社名で検索することはできません.プロジェクトのGithubページにはいくつかのオープンな問題がありますが、ここまで解決していません.
    https://github.com/monicahq/monica/issues/2069
    https://github.com/monicahq/monica/issues/1017
    回避策として、連絡先にPHPコードを微調整できます.追加の検索パラメータを追加することでPHPファイルを作成します.私は通常、アプリのコードの中で直接変更するようにしたくないが、ハードコーディングよりも他の方法はありません.
    あなたが追加することができます唯一の有用なパラメータは、連絡先の説明は、最初に会った情報や会社の名前です.残念なことに、彼らは別のテーブルに格納されているので、この回避策を使用して会話や活動を検索することはできません.誰かがこれのために回避策を見つけるならば、共有してください.
    コンテナ内で次の3つのコマンドを入力して、回避策を実装します.あなたはdocker exec ECSによって使用されたEC 2インスタンスからコンテナ内のコマンドを実行するコマンド構文.
    sed -i '/searchable_columns / a '\'description''\'\,'' /var/www/monica/app/Models/Contact/Contact.php
    sed -i '/searchable_columns / a '\'first_met_additional_info''\'\,'' /var/www/monica/app/Models/Contact/Contact.php
    sed -i '/searchable_columns / a '\'company''\'\,'' /var/www/monica/app/Models/Contact/Contact.php
    
    新しいモニカアプリコンテナーを起動するたびに、この手順を再実行する必要があります.

    次のステップのアイデア.


    ここで私は将来的に取り組んでいるかもしれないいくつかのことがあります.うまくいけば、私のお気に入りの個人的なCRMがより効率的に私を助けているので、より多くの空き時間を見つけます

    雲形成スタック


    これらのステップの展開を自動化するスタックを開発したい.アイデアはS 3バケット、IAMのユーザーとポリシー、オーロラServerless MySQL、VPC、EC 2インスタンス、ECSクラスタとタスク定義を含めることです.スタックによって作成されない唯一の部分はDNS別名で、ドメイン名とプロバイダーに固有です.

    全力で行く


    PHPがネイティブにサポートされているラムダRuncode環境として表示されませんが、独自のビルドを行うチュートリアルがいくつかあります.私は完全にモニカDockerからSAWフレームワークを使用してAWSラムダとAPIゲートウェイに基づいてServerlessアーキテクチャに移動したいと思います.

    Githubページ


    https://github.com/lautmat/docker-monicacrm-aws