docker-mailserver: addmailuser is slow when number of mailboxes increases (especially with NFS)
Bug Report
Context
Firstly thanks for a great container. The email software stack must be one of the most complex to implement !
I notice that when calling addmailuser it becomes very slow when number of mailboxes increases.
I did not notice slowness too much when using non-NFS e.g. local HDD or AWS EBS storage
Now I am using NFS (actually AWS EFS) storage since deploying as docker in AWS ECS.
For example I have 2500 mailboxes and a call to addmailuser takes 60 seconds.
I have removed some old inactive mailboxes and now have 500 mailboxes but a call to addmailuser now still takes 30 seconds. Seems too slow to add a single user.
I think the slowness is in the design of check-for-changes.sh. It detects change in postfix-accounts.cf and then loops through all lines in this file, trying to add each user or update its password for each line. This may give good consistency of user data across dovecot etc… but is very inefficient. If it saved a copy of the last successful processing of file postfix-accounts.cf, then it could diff the new file against that copy and detect only one line is new and then create the new user. That would probably be 0.5 secs or less.
There is a slight risk that the copy of postfix-accounts.cf becomes incorrect, through script crashing. To help fix this the start on the container could process the entire postfix-accounts.cf (current behaviour) to fix any config “drift”.
Arguably this is not a Bug but a Feature Request.
What is affected by this bug?
Speed of addmailuser command.
When does this occur?
When number of mailboxes is high (>=500) and storage is NFS.
How do we replicate the issue?
- NFS storage
- create > 500 mailboxes
- time execution of addmailuser
Behavior
Actual Behavior
Expected Behavior
Your Environment
Using latest EDGE docker image from dockerhub. AWS ECS docker on EC2 nodes. EFS storage from all volumes e.g. /var/mail and /tmp/docker-mailserver
Environment Variables
From a docker ECS service spec :
{ "name" : "SSL_TYPE", "value" : "manual" },
{ "name" : "SSL_CERT_PATH", "value" : "/tmp/ssl/mail.qa-mail.tradingapps.com.crt" },
{ "name" : "SSL_KEY_PATH", "value" : "/tmp/ssl/mail.qa-mail.tradingapps.com.key" },
{ "name" : "DMS_DEBUG", "value" : "0" },
{ "name" : "ENABLE_CLAMAV", "value" : "0" },
{ "name" : "ONE_DIR", "value" : "1" },
{ "name" : "ENABLE_POP3", "value" : "1" },
{ "name" : "ENABLE_FAIL2BAN", "value" : "0" },
{ "name" : "ENABLE_MANAGESIEVE", "value" : "" },
{ "name" : "OVERRIDE_HOSTNAME", "value" : "mail.qa-mail.tradingapps.com" },
{ "name" : "POSTMASTER_ADDRESS", "value" : "" },
{ "name" : "POSTSCREEN_ACTION", "value" : "enforce" },
{ "name" : "REPORT_RECIPIENT", "value" : "0" },
{ "name" : "REPORT_INTERVAL", "value" : "daily" },
{ "name" : "SMTP_ONLY", "value" : "" },
{ "name" : "TLS_LEVEL", "value" : "" },
{ "name" : "SPOOF_PROTECTION", "value" : "" },
{ "name" : "ENABLE_SRS", "value" : "0" },
{ "name" : "PERMIT_DOCKER", "value" : "network" },
{ "name" : "VIRUSMAILS_DELETE_DELAY", "value" : "" },
{ "name" : "ENABLE_POSTFIX_VIRTUAL_TRANSPORT", "value" : "" },
{ "name" : "POSTFIX_DAGENT", "value" : "" },
{ "name" : "ENABLE_SPAMASSASSIN", "value" : "0" },
{ "name" : "SA_TAG", "value" : "2.0" },
{ "name" : "SA_TAG2", "value" : "6.31" },
{ "name" : "SA_KILL", "value" : "6.31" },
{ "name" : "SA_SPAM_SUBJECT", "value" : "***SPAM*****" },
{ "name" : "ENABLE_FETCHMAIL", "value" : "0" },
{ "name" : "FETCHMAIL_POLL", "value" : "300" },
{ "name" : "ENABLE_LDAP", "value" : "" },
{ "name" : "LDAP_START_TLS", "value" : "" },
{ "name" : "LDAP_SERVER_HOST", "value" : "" },
{ "name" : "LDAP_SEARCH_BASE", "value" : "" },
{ "name" : "LDAP_BIND_DN", "value" : "" },
{ "name" : "LDAP_BIND_PW", "value" : "" },
{ "name" : "LDAP_QUERY_FILTER_USER", "value" : "" },
{ "name" : "LDAP_QUERY_FILTER_GROUP", "value" : "" },
{ "name" : "LDAP_QUERY_FILTER_ALIAS", "value" : "" },
{ "name" : "DOVECOT_TLS", "value" : "" },
{ "name" : "DOVECOT_USER_FILTER", "value" : "" },
{ "name" : "DOVECOT_PASS_FILTER", "value" : "" },
{ "name" : "ENABLE_POSTGREY", "value" : "0" },
{ "name" : "POSTGREY_DELAY", "value" : "300" },
{ "name" : "POSTGREY_MAX_AGE", "value" : "35" },
{ "name" : "POSTGREY_TEXT", "value" : "Delayed by postgrey" },
{ "name" : "ENABLE_SASLAUTHD", "value" : "" },
{ "name" : "SASLAUTHD_MECHANISMS", "value" : "1" },
{ "name" : "SASLAUTHD_MECH_OPTIONS", "value" : "rimap" },
{ "name" : "SASLAUTHD_LDAP_SERVER", "value" : "127.0.0.1" },
{ "name" : "SASLAUTHD_LDAP_SSL", "value" : "" },
{ "name" : "SASLAUTHD_LDAP_BIND_DN", "value" : "" },
{ "name" : "SASLAUTHD_LDAP_PASSWORD", "value" : "" },
{ "name" : "SASLAUTHD_LDAP_SEARCH_BASE", "value" : "" },
{ "name" : "SASLAUTHD_LDAP_FILTER", "value" : "" },
{ "name" : "SASL_PASSWD", "value" : "" },
{ "name" : "SRS_EXCLUDE_DOMAINS", "value" : "" },
{ "name" : "SRS_SECRET", "value" : "" },
{ "name" : "RELAY_HOST", "value" : "" },
{ "name" : "RELAY_PORT", "value" : "" },
{ "name" : "RELAY_USER", "value" : "" },
{ "name" : "RELAY_PASSWORD", "value" : "" }
Relevant Stack Traces
None.
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Reactions: 1
- Comments: 15 (13 by maintainers)
Sorry, hit the wrong button and closed this…
That will wait for check-for-changes to complete. So it’s related, but still points to slowness with check-for-changes. I agree with Casper that avoiding use of the container is a possible solution to get better speed.
Hmm, looks like a mobile app bug. Thanks!
For some reason I don’t have permission to remove labels. @wernerfred, can you assist?
Hey @davidcallen ,
That’s awesome. There is a repo that was started to add this functionality, though it might look different in the end. You can check it out in https://github.com/docker-mailserver/docker-mailserver-admin if you have some free time.
I’m not 100% but it seems like this would cause problems with the way we do testing. We can of course experiment and add new tests that prepare everything, wait for the check-for-changes and then look for all of the entries in all of the files/execute all of the list or lookup commands to make sure everything was added properly. That sounds like a daunting task personally, but not impossible 😅
The more I think about it, it seems like the admin/api project I linked to above sort of needs this though. You can find a discussion of achieving this here: https://github.com/docker-mailserver/docker-mailserver-admin/issues/3#issuecomment-877733258 and if a core queue existed for the docker-mailserver, then the API would just use it instead of doing its own thing. Very interesting!
Regardless, I opened a ticket for this (see the mentioned issue). In the meantime, I’ve added and am testing some optimizations for
check-for-changes.sh
which might help a bit. They can be found in https://github.com/NorseGaud/docker-mailserver/blob/check-for-changes-performance/target/scripts/check-for-changes.shNorseGaud is correct and that the “while loop” causes addmailuser to wait until check-for-changes.sh (unless running from a new container with setup.sh).
I’ll explain my use-case since that is why I call addmailuser from within the container. I am using docker-mailserver for a testing/QA mailserver and need automation to create new mailboxes for isolated test runs. To achieve the automation I extend the docker image by adding a small python webservice which can create new mailboxes by calling addmailuser. The tests make curl http requests to my “mail-admin” webservice. This seems like a valid approach IMHO.
Maybe check-for-changes.sh has simplicitly but inefficiency. My proposed “diff-ing” approach of the postfix-accounts.cf is maybe a bit awkward to achieve. Maybe either :
However I dont know the full complexity of docker-mailserver e.g. the dovecot.quotas and postfix-virtual.cf so am reluctant to start coding a fix, at this time
check-for-changes.sh
is not directly involved when usingaddmailuser
.What I think slows down the process of adding users is this: https://github.com/docker-mailserver/docker-mailserver/blob/45345b2f49ba52b6ef9efe6492fa3b99bd4f89ae/target/bin/addmailuser#L68-L75
That part is skipped, when not using a running container to add users.