<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های عرفان قلی زاده</title>
        <link>https://virgool.io/feed/@erfantk</link>
        <description>DevOps/SRE</description>
        <language>fa</language>
        <pubDate>2026-04-15 06:03:59</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/1734323/avatar/UXPpPZ.jpg?height=120&amp;width=120</url>
            <title>عرفان قلی زاده</title>
            <link>https://virgool.io/@erfantk</link>
        </image>

                    <item>
                <title>اسکن امنیتی ایمیج های داکری</title>
                <link>https://virgool.io/azki-posts/%D8%A7%D8%B3%DA%A9%D9%86-%D8%A7%D9%85%D9%86%DB%8C%D8%AA%DB%8C-%D8%A7%DB%8C%D9%85%DB%8C%D8%AC-%D9%87%D8%A7%DB%8C-%D8%AF%D8%A7%DA%A9%D8%B1%DB%8C-y5hj81nwftqj</link>
                <description>توی این مقاله میخوام در مورد روند ساخت یک پروژه برای خودکارسازی اسکن امنیتی ایمیج‌های داکر صحبت بکنم و پروژه ای رو با شما به اشتراک بزارم تا شما هم بتونید از مزایاش توی سازمانتون استفاده بکنید.دقیقا یادم نمیاد چه تاریخی بود که همکار خوبم علیرضا حمیدی داشت ابزارهای grype و trivy و ... رو با هم مقایسه میکرد و تفاوت هاش رو به ما ارائه میداد. بعد از اون جلسه تصمیم نهایی رو گرفتیم که با ابزار grype پیش بریم.اما چرا این همه زحمت؟ زمانی که برای یک سازمان بزرگ مثل ازکی کار میکنید باید بتونید محافظت از امنیت اطلاعات کاربران و سازمانتون رو توی لایه های مختلف پیاده سازی بکنید، یکی از اون لایه های ایمیج های داکر هست که عموما به خاطر نبودن ابزار آماده یا پولی بودن این ابزارها، نادیده گرفته میشه یا به صورت مرتب انجام نمیشه، ما توی ازکی دنبال راه حل مناسب بودیم و این شد که به سمت ساختن یک پروژه برای استاندار سازی خروجی اسکن های امنیتی ایمیج‌هامون رو آوردیم.من دست به کار شدم و شروع کردم به پیدا کردن یک راه حل مناسب برای این مشکل، اما چه نیازمندی هایی داشتیم؟ اول از همه این راهکار باید بتونه به صورت دوره ای اجرا بشه و نیاز به عملیات دستی نداشته باشه تا هزینه جدیدی برای اجرا به تیم اضافه نشه، نیازمندی دیگه ما این بود که بتونیم دیتایی هیستوریکال داشته باشیم تا در صورت نیاز بتونیم به بهبود تا بدتر شدن شرایط اشاره بکنیم. در همین راستا علیرضا پیشنهاد داد که از خروجی html ابزار grype استفاده بکنیم. خروجی رو به همه تیم ارائه داد و فوق العاده بود! یه صفحه html به صورت تک فایل و بسیار سبک، همینطور این فایل قابلیت کاستومایز شدن داشت.با این اطلاعاتی که به مرور زمان جمع کردیم شروع کردم به پیدا کردن یک راه حل مناسب، برای شروع یک ابزار CLI پایتون توسعه دادم که بتونه یک فایل، شامل لیستی از ایمیج‌های داکری، که نیاز به اسکن داره رو بخونه و با استفاده از دسترسی shell ابزار grype رو صدا بزنه و خروجی های html مورد نیاز رو آماده بکنه.خروجی ابزار ترمینالی پایتونخب حالا نیاز داریم که بتونیم فایل هایی که با پوشه بندی بر اساس تاریخ به صورت خروجی داریم رو توی مرورگر نشون بدیم. برای این کار هم از وب‌سرور nginx استفاده کردم و خروجی هایی که ساختم رو با استفاده از دستور autoindex به کاربران نمایش دادم. آیا این کافی بود؟ نه، اینکه خروجی پوشه ها رو ببینیم برای من کافی نبود و با استفاده از دستورات add_before_body و add_after_body توی nginx یک قالب هم به خروجی نمایش داده اضافه کردم و از حقه های regex مختلف استفاده کردم برای اینکه این قالب فایل های از پیش ساخته grype رو تحت تاثیر قرار نده و خرابشون نکنه. آیا کافی بود؟ بله :) .به تبدیل این پروژه به یک helm فکر کردم و تا مراحل خوبی هم پیش بردمش (توی هیستوری گیت میتونید ببینید)، ولی در نهایت پشیمون شدم و خروجی رو به شکل داکر کامپوز آماده کردم، دلیلم برای این کار چی بود؟ چون میخواستم همه بتونند از این سرویس استفاده بکنند و فقط برای کسایی که سرویس کوبرنتیز دارند جذاب نباشه (باور من این هست که توی اولویت بندی امروزم، کسی که کوبرنتیز داره خودش میتونه پروژه من رو تبدیل بکنه به manifest از روی داکر کامپوزی که ساختم).قبل از اجرای پروژه داخل دو فایل در صورت نیاز تغییر ایجاد بکنید. فایل اول یک فایل .env هست برای استفاده از ریپازتوری داکر کاستوم و فایل دوم images.txt هست برای معرفی کردم آدرس ایمیج هایی که میخواید اسکن بشه. توی عکس زیر هم میتونید ساختار پروژه خام رو مشاهده بکنید.ساختار فایل های پروژهبعد از پایان تنظیم کردم دو تا فایل مورد نظر حالا میتونید پروژه رو ران بکنید. برای اینکار یک دستور برای اجرا شدن وب‌سرور نیاز دارید و یک دستور دیگه که میتونید به صورت دوره‌ای اجرا بکنید یا با ابزاری مثل cron برای زمان های خاصی زمان بندی بکنید.دستورات مورد نیاز و یک نمونه از cron برای اجرا در ابتدای هر هفته رو براتون همین پایین گزاشتم:# Run webserver
docker compose up -d web

# Run the scan result generator
docker compose up --build generator

# Run the scan generator as a job in crontab
0 0 * * FRI root { cd /opt/image-sec-scan &amp;&amp; docker compose up --build generator; } &gt; /opt/image-sec-scan/run.log 2&gt;&amp;1بعد از اجرا به پرت ۸۸۸۸ (دیفالت) یا پرتی که داخل فایل .env کاستوم کردید سر بزنید و خروجی اسکن رو مشاهده کنید. تصویر نمونه خروجی اسکن با دیفالت پروژه:مسیر ایندکس اسکن هاخروجی نهایی اسکن یک داکر ایمیجتوی خروجی نهایی، میتونید سرچ کنید، فیلتر کنید و یا حتی خروجی pdf بگیرید!امیدوارم این راهکار برای شما مفید باشه و اگر نیاز بیشتر یا پیچیده‌تر دارید خوشحال میشم که مشارکت‌های شما رو توی پروژه داشته باشم.آدرس پروژه توی گیت هاب: github.com/erfantkerfan/image-sec-scanمن عرفان قلی زاده یک مهندس DevOps هستم و سعی میکنم از تجربیاتم که میتونه براتون مفید باشه به صورت منظم و نامنظم بلاگ بنویسم.</description>
                <category>عرفان قلی زاده</category>
                <author>عرفان قلی زاده</author>
                <pubDate>Thu, 05 Dec 2024 10:41:26 +0330</pubDate>
            </item>
                    <item>
                <title>پیاده سازی سرویس آرتیفکتوری جی‌فراگ</title>
                <link>https://virgool.io/@erfantk/%D9%BE%DB%8C%D8%A7%D8%AF%D9%87-%D8%B3%D8%A7%D8%B2%DB%8C-%D8%B3%D8%B1%D9%88%DB%8C%D8%B3-%D8%A2%D8%B1%D8%AA%DB%8C%D9%81%DA%A9%D8%AA%D9%88%D8%B1%DB%8C-%D8%AC%DB%8C-%D9%81%D8%B1%D8%A7%DA%AF-xgbnz2jptmt6</link>
                <description>بعد از انتشار مقاله قبلی من در مورد انتخاب jfrog container registry درخواست‌های زیادی داشتم که پیاده سازی رو هم توضیح بدم و این شد که این مقاله رو نوشتم. این‌بار پیاده سازی سرویس آرتیفکتوری JCR رو به صورت عملی و کامل براتون تو این مقاله توضیح دادم.فکر می‌کنم که نیازی نیست بیشتر از توضیحات ارائه شده توی مقاله ی قبلی از خوبی های سرویس jfrog براتون بگم. این سرویس بسیار قوی، دارای باگ‌های حداقلی و به‌روزرسانی‌های منظم هست. تجربه عملی من در ازکی هم نشون داده که این سرویس می‌تونه نیازمندی‌های تکنیکال پیچیده‌ی یک سازمان بزرگ رو پاسخگو باشه. ما چند سالی هست که این سرویس رو در ازکی پیاده‌سازی کردیم و ازش استفاده می‌کنیم.بریم سراغ پیاده سازی تا شما هم بتونید از این سرویس استفاده کنید.پیاده سازی سرویس jfrog artifactory نحوه پیاده سازی آرتیفکتوری جی فراگ:برای پیاده سازی سرویس jcr راه‌های متفاوتی مثل استفاده از داکر، استفاده از هلم چارت و یا استفاده از باینری‌های پکیج شده هست. من برای راحتی و هم‌چنین ساده‌سازی پیاده‌سازی دیتابیس، راهکار استفاده از docker compose رو توضیح میدم.برای شروع باید برید داخل صفحه دانلود jcr که احتمالا به راحتی نمی‌تونید اون رو داخل سایتش پیدا کنید. زمانی که روی لینک docker compose کلیک کنید براتون یک فایل با پسوند tar.gz دانلود میشه. فایل دانلود شده رو هر جایی که راحت هستید از حالت فشرده خارج کنید. دستور زیر برای خارج کردن آخرین نسخه از حالت فشرده در زمان نوشتن این مقاله هست:tar -xvf jfrog-artifactory-jcr-7.90.7-compose.tar.gzوارد پوشه‌ای که ایجاد شده بشید، حالا احتمالا اولین چیزی که خواهید دید یک اسکریپت برای راه‌اندازی به اسم config.sh هست.دومین چیزی که باید بهش توجه کنید، یک پوشه به اسم templates هست که داخلش یک سری فایل compose هست که با استفاده از ساختاری که دوست دارید سرویستون رو راه اندازی کنید، میتونید از هر کدوم استفاده کنید.برای شروع پیاده‌سازی ابتدا فایل .env رو باز کنید و مقدار مسیر ذخیره‌سازی دیتا هاتون رو ست کنید. برای مثال من این مقدار رو وارد کردم. دقت کنید این مسیر برای ذخیره تمام دیتاهای شما استفاده میشه.ROOT_DATA_DIR=/home/erfan/Downloads/jfrog/artifactory-jcr-7.90.7/artifactoryحالا می‌تونید از اسکریپتی که در موردش صحبت کردیم، استفاده کنید و یک سری مقادیر اولیه ست کنید. یادتون باشه که دستور زیر رو با دسترسی root اجرا کنید.bash config.sh

[host 127.0.1.1] enter
[additional node to an existing product cluster] n
[install PostgreSQL] y
[database password] mypassword
[confirm database password] mypasswordبعد از این مرحله، برای شما دستورات compose پیشنهادی برای راه اندازی چاپ میشه، اما باید یه سری تغییرات داخلش بدید که راحت‌تر بتونید پیش برید. یکی از کارهایی که باید کنید این هست که دو فایل دیتابیس و آرتیفکتوری رو ادغام کنید:tail -n +3 docker-compose-postgres.yaml &gt;&gt; docker-compose.yamlتوی همین فایل ایجاد شد،  مقدار پسورد postgres هم میتونید ست کنید تا بعدا یادتون نره. البته الزامی به انجام این کار نیست چون دیتابیس از قبل استارت زده شده.حالا کانتینر قبلی دیتابیس رو استاپ کنید و با استفاده از docker compose مجددا استارتش کنید:docker stop postgresql &amp;&amp; docker rm postgresql &amp;&amp; docker compose -p rt up -d postgresحالا برای ایجاد ارتباط درست سرویس آرتیفکتوری با دیتابیس، نیاز هست توی یکی از فایل های کانفیگ، تغییر لازم رو انجام بدید. با این تغییر مسیر دسترسی به دیتابیس از توی نتورک داکر ایجاد میشه:vim artifactory/var/etc/system.yaml
=== before:
url: jdbc:postgresql://127.0.1.1:5432/artifactory
=== after:
url: jdbc:postgresql://postgres:5432/artifactoryبعد از این قسمت باید سرویس آرتیفکتوری رو هم استارت کنید:docker compose -p rt up -dخب الان سرویس شما آماده هست و میتونید توی آدرس زیر وارد داشبورد آرتیفکتوری بشید و تنظیمات اولیه‌ی لازم مثل دامنه و ریپو های مورد نیاز رو انجام بدید.url: http://localhost:8082/
user: admin
password: passwordپیشنهاد میکنم که وب سرور خودتون رو جلوی سرویس بزارید (برای ssl حتما پیشنهاد میکنم)، نمونه فایل کانفیگ nginx رو هم براتون به اشتراک می‌ذارم:upstream jcr { 
        zone upstreams 64K; 
        server 127.0.0.1:8082; 
        keepalive 2; 
} 

server { 
    listen 443 ssl; 

    ssl_certificate /etc/letsencrypt/live/docker.erfantkerfan.ir/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/docker.erfantkerfan.ir/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf; 
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; 

    http2 on; 
    server_name docker.erfantkerfan.ir; 

    client_max_body_size 0; 
    chunked_transfer_encoding on; 

    location / { 
        proxy_pass http://jcr/; 
        proxy_set_header  Host              $http_host; 
        proxy_set_header  X-Real-IP         $remote_addr; 
        proxy_set_header  X-Forwarded-For   $proxy_add_x_forwarded_for; 
        proxy_set_header  X-Forwarded-Proto $scheme; 

        proxy_buffering off; 
        proxy_request_buffering off; 
    }
}در  پایان:من عرفان قلی زاده staff engineer ازکی، سعی کردم در دو قسمت سرویس آرتیفکتوری (جی‌فراگ) رو براتون توضیح بدم. در قسمت اول این مقاله نسبت به بررسی سرویس‌های مشابه جی‌فراگ و معرفی خود جی‌فراگ پرداختم و در قسمت دوم، که همین مقاله حال حاضر هست، پیاده‌سازی آرتیفکتوری جی‌فراگ رو توضیح دادم. بخش قابل توجهی از این تجربه‌ها در زمان راه‌اندازی این سرویس در زیرساخت ازکی به دست اومده و امروز داره در ازکی به خوبی کار می‌کنه.من توی این مقاله، مواردی رو اشاره کردم که در داکیومنت خود این سرویس به خوبی وجود نداره و فقط شما زمانی که به صورت واقعی این سرویس رو پیاده‌سازی کنید باهاش مواجه می‌شید و من سعی کردم فوت کوزه‌گری این پیاده‌سازی رو در اختیارتون بزارم. مثل همیشه شنوای نظرات ارزشمند شما هستم و خوشحال میشم موارد آموزشی که دوست دارید در موردش اطلاعات درستی به درست بیارید بهم اطلاع بدید تا در مورد اون‌ها بلاگ‌های آموزشی جدیدی آماده بکنم.</description>
                <category>عرفان قلی زاده</category>
                <author>عرفان قلی زاده</author>
                <pubDate>Fri, 09 Aug 2024 21:18:47 +0330</pubDate>
            </item>
                    <item>
                <title>تمیز کردن جی فراگ و نگاهی به انتخاب ریپازتوری</title>
                <link>https://virgool.io/@erfantk/how-to-cleanup-jfrog-repository-umgm4aqivwp9</link>
                <description>چند وقت پیش بود که دنبال بهترین ابزار برای استفاده به عنوان رجیستری/مخزن/ریپازتوری بودم.من همیشه دنبال بهترین ابزارها هستم، برای پیدا کردن بهترین ابزارها اول راجبشون اطلاعات کسب میکنم و کلی مطالعه میکنم، بعد وقت میزارم و عملکردشون رو تست میکنم و بعد با یه لیست از مزایا و معایب و نیازمندی های خودم، بهترین ابزار رو به عنوان برنده تاجگذاری میکنم.من چند تا گزینه توی ذهنم داشتم: harbor nexusjfrogجلد اول: زیبای آزادبررسی harborharbor رفتم سراغ  harbor که تو بررسی اولیه متوجه شدم سایت این ابزار خیلی تر و تمیز و بدون هیچ گام اضافه ای که سرعتت رو بیاره پایین، اجازه میده سرویس خودت رو هاست بکنی و پیش بری، تا اینجا برای من عالی بود.قدم بعدی، بررسی UI بود که اون هم فوق‌العاده بود!در مورد تنطیماتharbor هم بخوام بهتون اطلاعات بدم باید بگم که تنظیماتش عالی بود و ساده!معایب harbor:در مورد معایب و مشکلات harbor بخوام بهتون بگم اول از همه این که این مخزن صرفا یه رجیستری داکر هست (۱) و بقیه آرتیفکت های حاصل از ساخت پروژه رو نمیتونی توش ذخیره یا کش بکنی.فیچر دومی که باهاش به مشکل خوردم مخزن کش بود که اجازه میده یه ایمیج رو از یک آپ استریم بگیری و کش بکنی، ولی خب ما توی ایران زندگی میکنیم :) و نیاز داریم که برای اتصال به بیشتر رجیستری ها از پروکسی استفاده بکنیم. ساز و کار تنظیم پروکسی نداشت و با حقه هایی مثل ساختن ایمیج کاستوم از برنامه و ست کردن مقداری مثل http/https_proxy هم نتونستم به نتیجه ایده آل خودم برسم، پس با harbor  خداحافظی کردم و ابراز بعدی رو تست کردم.https://goharbor.io/جلد دوم: خشن و کارآمدبررسی nexusnexus خب گزینه بعدی nexus بود،سایت این ابزار ظاهر خوب و تر تمیزی داشت که تو نگاه  اول چشمم رو گرفت ولی وقتی موقع دانلود شد، علی‌رغم اینکه این برنامه OSS هست ولی یه دیوار ثبت نام داشت که باید ازش میگذشتی، خب اینو که دوست نداشتم (سلیقه شخصی نویسنده)، بعد این مرحله زمان تست رسیده بود.قدم اول: بررسی ظاهربسیار ساده و زشت اما کاربردی! در مورد تنظیماتش؟ تقریبا امکاناتی شبیه هاربر داشت ولی چون قبلش هاربور رو دیده بودم که نسخه زیباتر همین تنظیمات رو داشت چنگ خاصی به دل نمیزد.مزایا: خب تقریبا هر مدل آرتیفکتی رو که دلت بخواد توش داشت و میتونستی استفاده بکنی و اینکه اپن سورس بود که این مورد، کاملا مطابق سلیقه من بود.معایب: پروکسی چی؟ خب ساپورت میکنه اما به صورت یک جا، یعنی به صورت جداگانه برای هر ریپازیتوری نمیتونی از پروکسی متفاوت (باز هم از مشکلات ایرانه نه مشکلات استاندارد) یا گزینه خاموش یا روشن کردنش استفاده بکنی، به خاطر مشکلاتی که در امکانات ساپورت پروکسی و ظاهر نه چندان قشنگ nexus از این ابزار هم گذشتم و به سراغ تست ابزار بعدی رفتم.https://www.sonatype.com/جلد سوم: زیبای پیچیدهبررسی jfrogjfrogخب گزینه بعدی که داشتم jfrog بود، وقتی وارد سایت این ابزار شدم با دو گزینه مواجه شدم که باید انتخاب میکردم از  jfrog container registry استفاده کنم یا jfrog artifactory که در نهایت JCR انتخاب کردم.چرا JCR رو انتخاب کردم؟خب JCR رایگان بود و نیاز به هیچ کاری نداشت و از اونجایی هم که  فرصت کافی نداشتم که آرتیفکتوری رو بالا بیارم و بعد هم برم سراغ فایلای جاوای دوست داشتنی :/ و کرک بکنم انتخاب JCR بهترین گزینه بود.در نگاه اول ظاهری بسیار شیک داشت، دکمه ها برق میزدن و آیکون ها جذاب بودن.تنظیمات JCR تقریبا پیچیده بود اما این پیچیدگی کارآمد بود چون هر چی رو که یه حرفه ای لازم داشت فراهم میکرد. باید اضافه بکنم که jfrog یه اکو سیستم کامل هست و ابزار های بیشتری داره که در ترکیب با همدیگه قدرتمند تر میشن.ساپورت انواع ریپازتوری چطور؟ ویرچوآل ریپازتوری که ترکیب ریپازتوری لوکال و کش بود و خوب این واقعا عالیه!لاگ: زیباترین لاگ هایی که توی یه برنامه دیدم رو برای شما توی خروجی چاپ میکنه و قدر این ویژگی رو زمانی میدونیم که در حال دیباگ هستیم!پروکسی؟؟ میتونی هر چند تا بخوای تعریف بکنی و هر کدوم رو برای هر ریپازیتوری که میخوای استفاده بکنی.انتخاب نهایی: بله همین رو میبرم لطفا (۲)https://jfrog.com/king being crowned - Erfan Gholizade - DevOpsخب حالا که مخزن ریپازتوری مورد علاقم برای کار انتخاب کردم به یه دلیل خوب دلم برای harbor تنگ شد!این دلیل همون دلیلی هست که انگیزه ی من شد تا این مقاله رو بنویسم و با شما به اشتراک بزارم.چون پاک کردن آرتیفکت های قدیم توی هاربر مثل خوردن یه لیوان چایی توی بعد از ظهر سرد بودش، فقط کافی بود چند تا کلیک بکنی و تمام. برای آرتیفکتوری نیاز بود که یه راهکار رو از ابتدا خودم بنویسم، چون اسکریپتی که توی اینترنت و سایت رسمی آرتیفکتوری پیدا میکنید خیلی ساده هست و اصلا پیچیدگی های یه شرکت بزرگ رو شامل نمیشه.آستین بالا زدم و nvim رو باز کردم و شروع به کار کردم.یه کانفیگ فایل نوشتم که از شما یه آرایه از جاهایی که میخوای بگیری و پاک بکنی رو دریافت میکنه، داخل هر کدوم از این تارگت مسیر ها چند تا رشته تنظیمات میگیره، مثل اینکه کدوم ریپازتوری رو پاک بکنه، چه مسیری ازش رو پاک بکنه، تا چه زمانی رو پاک بکنه (مثلا یک هفته قبل یا یک ماه قبل) و اینکه آیا مورد خاصی هست که بخوای استثنا باشه و اونارو پاک نکنه.مثل همیشه به یه اسکریپت ساده کفایت نکردم و بهش یه سری امکانات مثل منوی داخل tui اضافه کردم و برای اینکه خیلی ساده بشه تست کرد و استفادش کرد هیچ ماژول اضافه تری داخلش استفاده نکردم.https://github.com/erfantkerfan/jfrog-cleanerاگر دوست دارید میتونید پروژه و اسکریپت من رو اینجا ببینید و اگر از این سولوشن استفاده میکنید میتونید توی بهتر کردن این پروژه بهم کمک بکنید.https://github.com/erfantkerfan/jfrog-cleanerپی نوشت:(۱): برای افراد خیلی باسواد: helm هم ساپورت میکنه(۲): این انتخاب برای مشاوره به یه شرکت کوچیک بودش ولی به احتمال زیاد مسیر انتخاب jfrog artifactory در صورتی که صرفا به داکر رجیستری نیاز ندارید بهتر خواهد بود.** اگر استقبال صورت بگیره مسیر کرک کردن نرم افزار jfrog artifactory هم توی یه مقاله دیگه توضیح و آموزش میدم.منتظر نظرات شما هستمعرفان قلی زاده یک دواپس :)</description>
                <category>عرفان قلی زاده</category>
                <author>عرفان قلی زاده</author>
                <pubDate>Sat, 20 Jan 2024 03:02:27 +0330</pubDate>
            </item>
                    <item>
                <title>بهینه سازی تصویر با resize و ارائه webp در nginx</title>
                <link>https://virgool.io/@erfantk/cdn-nginx-image-optimization-gm3lgi3ymwa3</link>
                <description>وب سایت شما موقع لود عکس ها کنده؟نمره سئو تصاویر سایت شما چند هست؟چند درصد از تصاویر سایتتون بهیته هست؟ برای بهینه سازی تصاویر از پلاگین استفاده میکنید؟با فرمت های مناسب برای تصاویر سایت که سئو فرندلی هم باشه آشنایی دارید؟چه جوری میتونیم از فرمت عکس webp استفاده کنیم اما به فرانت سایت دست نزنیم؟میخواید فرمت عکس webp رو ساپورت بکنید اما لینک های قدیمی خراب نشه و لینک های جدید هم براتون توی سئو مشکل ایجاد نکنه؟خب پس حتما این مقاله رو بخونید!من عرفان قلی زاده هستم و در حال حاضر DevOps/SRE در شرکت وندار هستم، با توجه به اینکه تو دنیای سرچ انجین های امروز مخصوصا گوگل، SEO نقش مهمی در وب سایت های ما داره، تصمیم گرفتم که برای بهینه سازی لود عکس ها و سئو تصاویر با استفاده از وب سرور nginx یه مطلب رو براتون شرح بدم که هم برای افرادی که با سرور کار میکنند هم افرادی که در زمینه سئو تمرکز دارند به شدت توصیه میشه وقت بزارن و مطاله کنن.بهینه سازی عکس با انجین ایکس توی این مطلب من فرض میکنم که شما کار با nginx رو بلد هستید و دارید گوشه های تاریک nginx رو با من کشف میکنید. (راستی چند روز پیش cloudflare اعلام کرد که دیگه nginx برای زیر ساختش کافی نیست و برای خودش یه محصول جدید رو از صفر با زبون Rust نوشته - در ستایش nginx بود)لینک پروژه توی گیت هاب هم ببینید، به خوبی داکیومنت شده و انتهای مقاله هست⭐شروع این ماجرا زمانی بود که من در شرکتی کار میکردم که عکس‌های بسیار زیادی در هر صفحه داشتیم و نیاز به بهینه‌سازی عکس‌ها هم برای بهبود سرعت سایت و هم برای بالا بردن امتیاز سئو به شدت حس میشد. برای انجام این کار قبل از اینکه من به این تیم ملحق بشم از همچین تنظیماتی استفاده میشد:map $arg_width $width {
        default     &#039;-&#039;;
        &amp;quot~[0-9]+&amp;quot    $arg_width;
}
map $arg_height $height {
        default     &#039;-&#039;;
        &amp;quot~[0-9]+&amp;quot    $arg_height;
}
server {
        listen       80;
        server_name  _ ;
        location ~* \.(?:jpg|jpeg|png|webp)$ {
                root   /usr/share/nginx/html;
                try_files $uri $uri/ =404;
                image_filter_jpeg_quality 95;
                image_filter_webp_quality 100;
                image_filter_interlace on;
                image_filter_buffer 10M;
                image_filter resize $width $height;
                image_filter crop $width $height;
                image_filter_transparency on;
        }
}خب این کانفیگ داره چیکار میکنه؟ما اول داریم پسوند های عکس رو توی یه location بلاک میگیریم و بعدش با استفاده از آرگومان هایی که قبلا از query string دریافت کردیم عکس رو به صورت اتوماتیک توی وب سرور تغییر اندازه میدیم.اینجوری هر زمان که درخواستی عادی ارسال بشه کاربر عکس رو به شکل معمولی میبینه اما وقتی که با استفاده از query string به همراه درخواستش width و height ارسال بکنه عکس مناسب خودش رو میبینه.مزیت این کار چیه:۱. نیاز نیست تعداد زیادی عکس با اندازه های مختلف تولید کنیم.۲. نمره SEO ما افزایش پیدا میکنه چون عکس متناسب با اندازه صفحه دستگاه کاربر رو براش فرستادیم.۳. سرعت سایت افزایش قابل ملاحظه ای پیدا میکنه.خب تا اینجا که عالی بود ... اما یه روزی رسید که اعلام شد بهتره سایت ها از فرمت عکس webp  برای تصاویرشون استفاده کنن، این فرمت توسط خود گوگل ارائه شده و با  حجم خیلی کمتر (توی تست های من در نمونه های تعداد بالا حدود یک پنجم حجم - در تعداد زیادی از عکس ها حتی یک دهم حجم اصلی) همون کیفیت jpg رو به ما میده (حتما میدونید که در ۹۹ درصد مواقع توی وب نیاز به استفاده از png نیست!)برای این کار روش های متفاوتی هست میتونیم مثل روشی که برای resize استفاده کردیم به اصطلاح on-the-fly عکس رو تبدیل کنیم اما من با این سیستم خیلی موافق نبودم و دوست داشتم که سیستم مقداری بهینه تر و هوشمند تر کار بکنه.اما اجازه بدید شمارو با چالش اصلی این قسمت آشنا بکنم ...هر دستگاهی از webp ساپورت نمیکنه!برای دور زدن این محدودیت میشه از یکی از هدرهایی که توی درخواست ارسال میشه به اسم accept header استفاده کرد.خب بریم تنظیمات رو ببینیم بعد راجبش حرف میزنم.map $http_accept $webp_suffix {
default   &amp;quot&amp;quot
&amp;quot~*webp&amp;quot &amp;quot.webp&amp;quot
}
...
try_files $uri$webp_suffix $uri =404;
...توی بلاک map اول چک میکنیم توی آرایه ای که کاربر برای فرمت هایی که دستگاه ساپورت میکنه webp رو فرستاده یا نه، اگر موجود باشه مقدار webp_suffix رو پر میکنیم در غیر اینصورت این مقدار خالی میمونه.با تغییر قسمت try_files نسبت به تیکه کد قبلی کاری میکنیم که در صورتی که کاربر ساپورت لازم رو داشت، عکس با فرمت webp براش ارسال بشه.خب هوشمندی این کجا بود؟؟۱. زمانی که شما پسوند webp رو موجود نداشته باشید کاربر بدون هیچ مشکلی پسوند اصلی رو دریافت میکنه.۲. زمانی که پسوند webp موجود باشه و کاربر هم ساپورت بکنه بدون تغییر url و redirect کاربر محتوای webp براش ارسال میشه (با همون پسوند اصلی ولی content-type مشخص میکنه که webp هست).۳. ابزارهای SEO چون این فرمت رو ساپورت میکنند متوجه این مساله میشن که شما عکس webp دارید.تا اینجا مسائل مربوط به گذشته بودند اما امروز، امروزه و باید به چالش های جدید برسیم ...از اونجایی که مسئله high-availability بسیار مهم هست، من چند سالی میشه که یک کلاستر object storage رو مثل ceph و minio به جای لوکال استوریج یا انواع استوریج های قدیمی پیشنهاد میکنم اما ...من با minio راحت تر بودم و در مقایسه هایی که داشتم برای مصارفی که ما داریم بهتر هست اما تمام توضیحات و تیکه کدهایی که بالا بود زمانی کار میکرد که ما به عکس به شکل یک فایل لوکال دسترسی داشتیم ...توی همچین شرایطی بود که من پیشنهاد دادم که برای یکی از جلسات coffee technology توی وندار من روی این موضوع کار بکنم و حتی بیشتر پیش برم و ببینم زیرساختی مثل کلودفلر و نسخه کپی ایرانیش ابرآروان به عنوان یک CDN چجوری اینکارو انجام میدن؟اگر تا اینجا متوجه نشدید که این حالت با دسترسی لوکال چه فرقی داره باید بگم که وقتی شما از minio استفاده میکنید باید درخواست رو proxy pass بکنید و ارسال فایل توسط زیرساخت minio انجام میشه.حتما تا اینجا مطلب رو با دقت خوندید، پس بخش resize و webp رو توی دو قسمت مجزا براتون توضیح نمیدم و مستقیم میرم سراغ کانفیگ نهایی:upstream minio_servers {
        server minio:9000 max_fails=0;
        keepalive 128;
}

location ~* \.(?:jpg|jpeg|png|webp)$ {
        root   /usr/share/nginx/html;
        try_files /dev/null @image_webp;
}
location @image_webp {
        proxy_pass http://minio_servers$uri$webp_suffix;
        image_filter_jpeg_quality 95;
        image_filter_webp_quality 100;
        image_filter_interlace on;
        image_filter_buffer 10M;
        image_filter resize $width $height;
        image_filter crop $width $height;
        image_filter_transparency on;
        error_page 404 415 = @image;
}
        location @image {
        proxy_pass http://minio_servers$uri;
        image_filter_jpeg_quality 95;
        image_filter_webp_quality 100;
        image_filter_interlace on;
        image_filter_buffer 10M;
        image_filter resize $width $height;
        image_filter crop $width $height;
        image_filter_transparency on;
}توی تیکه کد بالا ابتدا سرورهای upstream رو تعریف کردیم که برای ما minio هست (و برای یک CDN provider این قسمت تبدیل میشه به سرور های اصلی استفاده کننده از سرویس).بعد سعی کردیم که که تصاویر رو بفرستیم به بلاک @image_webp دقت کنید که قسمت /dev/null به خاطر اینکه nginx امکانش رو نداره که اولین آرگومان یه named location باشه ضروری هست و در تاثیر منفی هم در performance نداره.در صورتی که مرورگر کاربر فرمت عکس webp رو ساپورت نکنه (با هدر accept) در همین قسمت براش عکس اصلی ارسال میشه، در صورت اینکه ساپورت بکنه هم عکس webp براش با content-type درستی توی همون url ارسال میشه.فقط زمانی ما به بلاک @webp میریم که به هر دلیلی عکس موجود نباشه یا موقع تبدیل به خطا برخورد کنیم که در این حالت به عنوان fallback سراغ عکس اصلی میریم.در نهایت ...سعی کردم به زبان خیلی ساده یه راهکار اساسی و پیشرفته برای بهینه سازی تصاویر یک سایت ارائه بدم که هم برای همکارانم مفید و کارآمد باشه و هم برای بچه هایی که تو زمینه سئو تکنیکال دنبال تریک‌های حرفه ای هستن کارا باشه. فرمت webp در حال حاضر یکی از بهترین فرمت ها برای تصاویر یک سایت هست که علاوه بر گوگل بیشتر موتورهای جستجو هم ازش پشتیبانی میکنن تو این مقاله با هم یاد گرفتیم چه جوری فرمت یه عکس رو از سمت سرور به webp تبدیل کنیم بدون اینکه نه تغییری تو فرانت ایجاد بشه نه  تعداد زیادی لینک به ازای هر تصویر تو سایت ایجاد بشه. منتظر نظراتتون هم هستم، راستی تو لینکدین هم میتونید با من در ارتباط باشیدامیدوارم از این مطلب لذت ببرید و استفاده بکنید.بهتون گفتم که من از arch استفاده میکنم؟ ? شما از چی استفاده میکنید؟لینکدین من: https://www.linkedin.com/in/erfan-gholizadeلینک گیت هاب پروژه کامل این بلاگ: https://github.com/erfantkerfan/cdn-nginx-image-optimization</description>
                <category>عرفان قلی زاده</category>
                <author>عرفان قلی زاده</author>
                <pubDate>Sat, 17 Sep 2022 23:53:01 +0430</pubDate>
            </item>
            </channel>
</rss>