Saya ingin tahu apakah ada cara untuk menyiapkan cronjob / tugas untuk dijalankan setiap menit. Saat ini salah satu contoh saya seharusnya dapat menjalankan tugas ini.
Inilah yang saya coba lakukan di file konfigurasi tanpa hasil:
container_commands:
01cronjobs:
command: echo "*/1 * * * * root php /etc/httpd/myscript.php"
Saya tidak begitu yakin apakah ini cara yang benar untuk melakukannya
Ada ide?
Jawaban:
Beginilah cara saya menambahkan tugas cron ke Elastic Beanstalk:
Buat folder di root aplikasi Anda dengan nama .ebextensions jika belum ada. Kemudian buat file konfigurasi di dalam folder .ebextensions. Saya akan menggunakan example.config untuk tujuan ilustrasi. Kemudian tambahkan ini ke example.config
Ini adalah file konfigurasi YAML untuk Elastic Beanstalk. Pastikan saat Anda menyalin ini ke editor teks Anda bahwa editor teks Anda menggunakan spasi, bukan tab. Jika tidak, Anda akan mendapatkan kesalahan YAML saat Anda mendorong ini ke EB.
Jadi yang dilakukannya adalah membuat perintah bernama 01_some_cron_job. Perintah dijalankan dalam urutan abjad sehingga 01 memastikan itu dijalankan sebagai perintah pertama.
Perintah tersebut kemudian mengambil konten dari file bernama some_cron_job.txt dan menambahkannya ke file bernama some_cron_job di /etc/cron.d.
Perintah kemudian mengubah hak akses pada file /etc/cron.d/some_cron_job.
Kunci leader_only memastikan perintah hanya dijalankan pada turunan ec2 yang dianggap sebagai pemimpin. Daripada berjalan di setiap contoh ec2 yang mungkin Anda jalankan.
Kemudian buat file bernama some_cron_job.txt di dalam folder .ebextensions. Anda akan menempatkan pekerjaan cron Anda di file ini.
Jadi contohnya:
Jadi tugas cron ini akan berjalan setiap menit setiap jam setiap hari sebagai pengguna root dan membuang hasilnya ke / dev / null. / usr / bin / php adalah jalur ke php. Kemudian ganti some-php-script-here dengan path ke file php Anda. Ini jelas mengasumsikan pekerjaan cron Anda perlu menjalankan file PHP.
Juga, pastikan file some_cron_job.txt memiliki baris baru di akhir file seperti di komentar. Jika tidak, cron tidak akan berjalan.
Pembaruan: Ada masalah dengan solusi ini saat Elastic Beanstalk meningkatkan skala instans Anda. Misalnya, Anda memiliki satu instance dengan tugas cron sedang berjalan. Anda mendapatkan peningkatan lalu lintas sehingga Elastic Beanstalk menskalakan Anda hingga dua contoh. Leader_only akan memastikan Anda hanya memiliki satu tugas cron yang berjalan di antara dua contoh. Lalu lintas Anda menurun dan Elastic Beanstalk menurunkan Anda ke satu contoh. Namun alih-alih menghentikan instance kedua, Elastic Beanstalk menghentikan instance pertama yang menjadi pemimpin. Sekarang Anda tidak memiliki tugas cron apa pun yang berjalan karena tugas tersebut hanya berjalan pada instance pertama yang dihentikan. Lihat komentar di bawah.
Pembaruan 2: Hanya memperjelas ini dari komentar di bawah ini: AWS sekarang memiliki perlindungan terhadap penghentian instans otomatis. Aktifkan saja pada contoh pemimpin Anda dan Anda siap melakukannya. - Nicolás Arévalo 28 Oktober '16 pukul 9:23
sumber
01_some_cron_job
untuk02_some_cron_job
dan ditambah01_remove_cron_jobs
dengan berikut ini:command: "rm /etc/cron.d/cron_jobs || exit 0"
. Dengan begitu, setelah setiap penerapan, hanya pemimpin yang akan memilikicron_jobs
file tersebut. Jika pemimpin berubah, Anda hanya dapat menerapkan kembali dan crons akan diperbaiki untuk dijalankan sekali lagi.leader_only
properti. Ini hanya digunakan selama penerapan dan jika Anda menurunkan skala atau instans "pemimpin" Anda gagal, Anda pasti memiliki referensiIni adalah cara resmi untuk melakukannya sekarang (2015+). Silakan coba ini dulu, sejauh ini metode termudah yang tersedia saat ini dan paling dapat diandalkan juga.
Menurut dokumen saat ini, seseorang dapat menjalankan tugas berkala pada apa yang disebut tingkat pekerja .
Mengutip dokumentasi:
Yang juga menarik adalah bagian tentang cron.yaml :
Pembaruan: Kami bisa mendapatkan pekerjaan ini. Berikut adalah beberapa hal penting dari pengalaman kami (platform Node.js):
eb ssh
), dan jalankancat /var/log/aws-sqsd/default.log
. Ini harus melaporkan sebagaiaws-sqsd 2.0 (2015-02-18)
. Jika Anda tidak memiliki versi 2.0, ada yang salah saat membuat lingkungan Anda dan Anda perlu membuat yang baru seperti yang disebutkan di atas.sumber
Mengenai respons jamieb, dan seperti yang disebutkan alrdinleal, Anda dapat menggunakan properti 'leader_only' untuk memastikan bahwa hanya satu instans EC2 yang menjalankan tugas cron.
Kutipan diambil dari http://docs.amazonwebservices.com/elasticbeanstalk/latest/dg/customize-containers-ec2.html :
Saya mencoba untuk mencapai hal serupa di eb saya, jadi akan memperbarui posting saya jika saya menyelesaikannya.
MEMPERBARUI:
Oke, sekarang saya memiliki cronjobs yang berfungsi menggunakan konfigurasi eb berikut:
Pada dasarnya, saya membuat file temp dengan cronjobs dan kemudian mengatur crontab untuk membaca dari file temp, kemudian menghapus file temp sesudahnya. Semoga ini membantu.
sumber
Seperti disebutkan di atas, kelemahan mendasar dalam menetapkan konfigurasi crontab adalah bahwa hal itu hanya terjadi saat penerapan. Saat cluster ditingkatkan secara otomatis, dan kemudian turun, ini disukai juga untuk menjadi server pertama yang dimatikan. Selain itu, tidak akan ada fail-over, yang bagi saya sangat penting.
Saya melakukan penelitian, lalu berbicara dengan spesialis akun AWS kami untuk menyampaikan ide dan memvalidasi solusi yang saya hasilkan. Anda dapat melakukannya dengan OpsWorks , meskipun ini seperti menggunakan rumah untuk membunuh lalat. Dimungkinkan juga untuk menggunakan Data Pipeline dengan Task Runner , tetapi ini memiliki kemampuan terbatas dalam skrip yang dapat dieksekusi, dan saya harus dapat menjalankan skrip PHP, dengan akses ke seluruh basis kode. Anda juga dapat mendedikasikan instans EC2 di luar cluster ElasticBeanstalk, tetapi Anda tidak akan mengalami fail-over lagi.
Jadi inilah yang saya temukan, yang tampaknya tidak konvensional (seperti komentar perwakilan AWS) dan dapat dianggap sebagai peretasan, tetapi berfungsi dan solid dengan fail-over. Saya memilih solusi pengkodean menggunakan SDK, yang akan saya tunjukkan dalam PHP, meskipun Anda dapat melakukan metode yang sama dalam bahasa apa pun yang Anda inginkan.
Jadi menelusuri ini dan bagaimana cara kerjanya ... Anda memanggil skrip dari crontab seperti yang biasa Anda lakukan pada setiap instans EC2. Setiap skrip menyertakan ini di awal (atau menyertakan satu file untuk masing-masing, saat saya menggunakannya), yang menetapkan objek ElasticBeanstalk dan mengambil daftar semua contoh. Ini hanya menggunakan server pertama dalam daftar, dan memeriksa apakah itu cocok dengan dirinya sendiri, yang jika terus berlanjut, jika tidak maka mati dan ditutup. Saya telah memeriksa dan daftar yang dikembalikan tampaknya konsisten, yang secara teknis hanya perlu konsisten selama satu menit atau lebih, karena setiap contoh menjalankan cron yang dijadwalkan. Jika memang berubah, itu tidak masalah, karena lagi itu hanya relevan untuk jendela kecil itu.
Ini tidak elegan dengan cara apa pun, tetapi sesuai dengan kebutuhan khusus kami - yang tidak meningkatkan biaya dengan layanan tambahan atau harus memiliki instans EC2 khusus, dan akan mengalami kegagalan jika terjadi kegagalan. Skrip cron kami menjalankan skrip pemeliharaan yang ditempatkan ke SQS dan setiap server dalam cluster membantu mengeksekusi. Setidaknya ini dapat memberi Anda pilihan alternatif jika sesuai dengan kebutuhan Anda.
-Davey
sumber
$instanceId = file_get_contents("http://instance-data/latest/meta-data/instance-id");
Kemudian gunakan saja $ instanceId var itu untuk melakukan perbandingan.Saya berbicara dengan agen dukungan AWS dan inilah cara kami membuat ini berhasil untuk saya. Solusi 2015:
Buat file di direktori .ebextensions Anda dengan nama_file_anda.config. Di input file konfigurasi:
Solusi ini memiliki 2 kekurangan:
Solusi:
Peringatan:
Anda tidak perlu menyetel Peran IAM jika Anda menggunakan peran pohon kacang default.
sumber
Jika Anda menggunakan Rails, Anda dapat menggunakan permata batang kacang yang elastis . Ini memungkinkan Anda menjalankan tugas cron pada semua instans atau hanya satu. Ia memeriksa setiap menit untuk memastikan bahwa hanya ada satu contoh "pemimpin", dan secara otomatis akan mempromosikan satu server menjadi "pemimpin" jika tidak ada. Ini diperlukan karena Elastic Beanstalk hanya memiliki konsep pemimpin selama penerapan dan dapat menutup instance apa pun kapan pun saat penskalaan.
UPDATE Saya beralih menggunakan AWS OpsWorks dan saya tidak lagi menjaga permata ini. Jika Anda membutuhkan lebih banyak fungsionalitas daripada yang tersedia di dasar-dasar Elastic Beanstalk, saya sangat menyarankan Anda untuk beralih ke OpsWorks.
sumber
Anda benar-benar tidak ingin menjalankan tugas cron di Elastic Beanstalk. Karena Anda akan memiliki banyak contoh aplikasi, ini dapat menyebabkan kondisi balapan dan masalah ganjil lainnya. Saya baru - baru ini membuat blog tentang ini (tip ke-4 atau ke-5 di bawah halaman). Versi pendek: Tergantung pada aplikasi, menggunakan antrian pekerjaan seperti SQS atau solusi pihak ketiga seperti iron.io .
sumber
2017: Jika Anda menggunakan Laravel5 +
Anda hanya perlu 2 menit untuk mengkonfigurasinya:
instal laravel-aws-worker
composer require dusterio/laravel-aws-worker
tambahkan cron.yaml ke folder root:
Itu dia!
Semua tugas Anda
App\Console\Kernel
sekarang akan dieksekusiInstruksi dan penjelasan mendetail: https://github.com/dusterio/laravel-aws-worker
Cara menulis tugas di dalam Laravel: https://laravel.com/docs/5.4/scheduling
sumber
Solusi yang lebih mudah dibaca menggunakan
files
alih-alihcontainer_commands
:Perhatikan bahwa format ini berbeda dari format crontab biasa yang menetapkan pengguna untuk menjalankan perintah sebagai.
sumber
Kontribusi 1 sen saya untuk 2018
Berikut adalah cara yang tepat untuk melakukannya (menggunakan
django/python
dandjango_crontab
aplikasi):di dalam
.ebextensions
folder buat file seperti ini98_cron.config
:Ini harus menjadi
container_commands
gantinyacommands
sumber
Seseorang bertanya-tanya tentang masalah penskalaan otomatis hanya pemimpin saat pemimpin baru muncul. Sepertinya saya tidak tahu bagaimana membalas komentar mereka, tetapi lihat tautan ini: http://blog.paulopoiati.com/2013/08/25/running-cron-in-elastic-beanstalk-auto-scaling- lingkungan Hidup/
sumber
Contoh terbaru dari Amazon adalah yang termudah dan paling efisien (tugas berkala):
https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/using-features-managing-env-tiers.html
tempat Anda membuat tingkat pekerja terpisah untuk menjalankan salah satu tugas cron Anda. Buat file cron.yaml dan letakkan di folder root Anda. Satu masalah yang saya hadapi (setelah cron tampaknya tidak dijalankan) adalah menemukan bahwa CodePipeline saya tidak memiliki kewenangan untuk melakukan modifikasi dynamodb. Berdasarkan itu setelah menambahkan akses FullDynamoDB di bawah IAM -> peran -> saluran Anda dan menerapkan ulang (batang kacang elastis), itu bekerja dengan sempurna.
sumber
Berikut penjelasan lengkap solusinya:
http://blog.paulopoiati.com/2013/08/25/running-cron-in-elastic-beanstalk-auto-scaling-environment/
sumber
Jadi kami telah berjuang dengan ini selama beberapa waktu dan setelah beberapa diskusi dengan perwakilan AWS, saya akhirnya menemukan apa yang menurut saya adalah solusi terbaik.
Menggunakan tingkat pekerja dengan cron.yaml jelas merupakan perbaikan termudah. Namun, dokumentasi tidak menjelaskan dengan jelas bahwa ini akan menempatkan pekerjaan di akhir antrian SQS yang Anda gunakan untuk benar-benar menjalankan pekerjaan Anda. Jika tugas cron Anda peka waktu (sebanyak mungkin), ini tidak dapat diterima, karena akan bergantung pada ukuran antrian. Salah satu opsinya adalah menggunakan lingkungan yang benar-benar terpisah hanya untuk menjalankan tugas cron, tapi menurut saya itu berlebihan.
Beberapa opsi lain, seperti memeriksa untuk melihat apakah Anda adalah contoh pertama dalam daftar, juga tidak ideal. Bagaimana jika instance pertama saat ini sedang dalam proses penonaktifan?
Perlindungan instans juga dapat menimbulkan masalah - bagaimana jika instans itu terkunci / dibekukan?
Yang penting untuk dipahami adalah bagaimana AWS sendiri mengelola fungsionalitas cron.yaml. Ada daemon SQS yang menggunakan tabel Dynamo untuk menangani "pemilihan pemimpin". Ini sering menulis ke tabel ini, dan jika pemimpin saat ini belum menulis dalam waktu singkat, contoh berikutnya akan mengambil alih sebagai pemimpin. Beginilah cara daemon memutuskan instance mana yang akan mengaktifkan pekerjaan ke antrean SQS.
Kita dapat menggunakan kembali fungsionalitas yang ada daripada mencoba menulis ulang fungsi kita sendiri. Anda dapat melihat solusi lengkapnya di sini: https://gist.github.com/dorner/4517fe2b8c79ccb3971084ec28267f27
Itu ada di Ruby, tetapi Anda dapat dengan mudah menyesuaikannya dengan bahasa lain yang memiliki AWS SDK. Pada dasarnya, ini memeriksa pemimpin saat ini, kemudian memeriksa negara bagian untuk memastikannya dalam keadaan baik. Ini akan berulang sampai ada pemimpin saat ini dalam keadaan baik, dan jika contoh saat ini adalah pemimpin, jalankan pekerjaan.
sumber
http://docs.aws.amazon.com/autoscaling/latest/userguide/as-instance-termination.html#instance-protection
sumber
Saya punya solusi lain untuk ini jika file php perlu dijalankan melalui cron dan jika Anda telah menetapkan instance NAT apa pun maka Anda dapat meletakkan cronjob pada instance NAT dan menjalankan file php melalui wget.
sumber
berikut adalah perbaikan jika Anda ingin melakukan ini di PHP. Anda hanya perlu cronjob.config di folder .ebextensions Anda untuk membuatnya berfungsi seperti ini.
envvars mendapatkan variabel lingkungan untuk file. Anda dapat men-debug output di tmp / sendemail.log seperti di atas.
Semoga ini membantu seseorang karena pasti membantu kami!
sumber
Berdasarkan prinsip-prinsip jawaban dari user1599237 , di mana Anda membiarkan cron job berjalan di semua contoh tetapi kemudian di awal pekerjaan menentukan apakah mereka harus diizinkan untuk berjalan, saya telah membuat solusi lain.
Alih-alih melihat instans yang berjalan (dan harus menyimpan kunci dan rahasia AWS Anda), saya menggunakan database MySQL yang sudah saya sambungkan dari semua instans.
Tidak ada kerugiannya, hanya positifnya:
Alternatifnya, Anda juga dapat menggunakan sistem file yang umum dibagikan (seperti AWS EFS melalui protokol NFS) daripada database.
Solusi berikut dibuat dalam kerangka PHP Yii tetapi Anda dapat dengan mudah menyesuaikannya untuk kerangka kerja dan bahasa lain. Juga penangan pengecualian
Yii::$app->system
adalah modul saya sendiri. Gantilah dengan apa pun yang Anda gunakan./** * Obtain an exclusive lock to ensure only one instance or worker executes a job * * Examples: * * `php /var/app/current/yii process/lock 60 empty-trash php /var/app/current/yii maintenance/empty-trash` * `php /var/app/current/yii process/lock 60 empty-trash php /var/app/current/yii maintenance/empty-trash StdOUT./test.log` * `php /var/app/current/yii process/lock 60 "empty trash" php /var/app/current/yii maintenance/empty-trash StdOUT./test.log StdERR.ditto` * `php /var/app/current/yii process/lock 60 "empty trash" php /var/app/current/yii maintenance/empty-trash StdOUT./output.log StdERR./error.log` * * Arguments are understood as follows: * - First: Duration of the lock in minutes * - Second: Job name (surround with quotes if it contains spaces) * - The rest: Command to execute. Instead of writing `>` and `2>` for redirecting output you need to write `StdOUT` and `StdERR` respectively. To redirect stderr to stdout write `StdERR.ditto`. * * Command will be executed in the background. If determined that it should not be executed the script will terminate silently. */ public function actionLock() { $argsAll = $args = func_get_args(); if (!is_numeric($args[0])) { \Yii::$app->system->error('Duration for obtaining process lock is not numeric.', ['Args' => $argsAll]); } if (!$args[1]) { \Yii::$app->system->error('Job name for obtaining process lock is missing.', ['Args' => $argsAll]); } $durationMins = $args[0]; $jobName = $args[1]; $instanceID = null; unset($args[0], $args[1]); $command = trim(implode(' ', $args)); if (!$command) { \Yii::$app->system->error('Command to execute after obtaining process lock is missing.', ['Args' => $argsAll]); } // If using AWS Elastic Beanstalk retrieve the instance ID if (file_exists('/etc/elasticbeanstalk/.aws-eb-system-initialized')) { if ($awsEb = file_get_contents('/etc/elasticbeanstalk/.aws-eb-system-initialized')) { $awsEb = json_decode($awsEb); if (is_object($awsEb) && $awsEb->instance_id) { $instanceID = $awsEb->instance_id; } } } // Obtain lock $updateColumns = false; //do nothing if record already exists $affectedRows = \Yii::$app->db->createCommand()->upsert('system_job_locks', [ 'job_name' => $jobName, 'locked' => gmdate('Y-m-d H:i:s'), 'duration' => $durationMins, 'source' => $instanceID, ], $updateColumns)->execute(); // The SQL generated: INSERT INTO system_job_locks (job_name, locked, duration, source) VALUES ('some-name', '2019-04-22 17:24:39', 60, 'i-HmkDAZ9S5G5G') ON DUPLICATE KEY UPDATE job_name = job_name if ($affectedRows == 0) { // record already exists, check if lock has expired $affectedRows = \Yii::$app->db->createCommand()->update('system_job_locks', [ 'locked' => gmdate('Y-m-d H:i:s'), 'duration' => $durationMins, 'source' => $instanceID, ], 'job_name = :jobName AND DATE_ADD(locked, INTERVAL duration MINUTE) < NOW()', ['jobName' => $jobName] )->execute(); // The SQL generated: UPDATE system_job_locks SET locked = '2019-04-22 17:24:39', duration = 60, source = 'i-HmkDAZ9S5G5G' WHERE job_name = 'clean-trash' AND DATE_ADD(locked, INTERVAL duration MINUTE) < NOW() if ($affectedRows == 0) { // We could not obtain a lock (since another process already has it) so do not execute the command exit; } } // Handle redirection of stdout and stderr $command = str_replace('StdOUT', '>', $command); $command = str_replace('StdERR.ditto', '2>&1', $command); $command = str_replace('StdERR', '2>', $command); // Execute the command as a background process so we can exit the current process $command .= ' &'; $output = []; $exitcode = null; exec($command, $output, $exitcode); exit($exitcode); }
Ini adalah skema database yang saya gunakan:
CREATE TABLE `system_job_locks` ( `job_name` VARCHAR(50) NOT NULL, `locked` DATETIME NOT NULL COMMENT 'UTC', `duration` SMALLINT(5) UNSIGNED NOT NULL COMMENT 'Minutes', `source` VARCHAR(255) NULL DEFAULT NULL, PRIMARY KEY (`job_name`) )
sumber