पायथन परियोजनाओं के लिए डॉकर छवि बनाते समय संकुल को पुनः स्थापित करने से कैसे बचें?


128

मेरी डॉकरीफाइल कुछ इस तरह है

FROM my/base

ADD . /srv
RUN pip install -r requirements.txt
RUN python setup.py install

ENTRYPOINT ["run_server"]

हर बार जब मैं एक नई छवि बनाता हूं, तो निर्भरता को फिर से स्थापित करना होगा, जो मेरे क्षेत्र में बहुत धीमी गति से हो सकता है।

एक तरह से मुझे लगता cacheहै कि जो पैकेज स्थापित किए गए हैं वे my/baseइस तरह की नई छवियों के साथ छवि को ओवरराइड करने के लिए हैं :

docker build -t new_image_1 .
docker tag new_image_1 my/base

इसलिए अगली बार जब मैं इस डॉकरीफाइल के साथ निर्माण करता हूं, तो मेरे / बेस में पहले से ही कुछ पैकेज स्थापित हो जाते हैं।

लेकिन इस समाधान में दो समस्याएं हैं:

  1. आधार छवि को ओवरराइड करना हमेशा संभव नहीं होता है
  2. आधार छवि बड़ी और बड़ी होती जाती है क्योंकि उस पर नई छवियां बिछाई जाती हैं

तो इस समस्या को हल करने के लिए मैं किस बेहतर समाधान का उपयोग कर सकता हूं?

संपादित करें ##:

मेरी मशीन पर डॉकटर के बारे में कुछ जानकारी:

  test  docker version
Client version: 1.1.2
Client API version: 1.13
Go version (client): go1.2.1
Git commit (client): d84a070
Server version: 1.1.2
Server API version: 1.13
Go version (server): go1.2.1
Git commit (server): d84a070
  test  docker info
Containers: 0
Images: 56
Storage Driver: aufs
 Root Dir: /var/lib/docker/aufs
 Dirs: 56
Execution Driver: native-0.2
Kernel Version: 3.13.0-29-generic
WARNING: No swap limit support

क्या आपने अपनी छवि बनाने के बाद मध्यवर्ती छवि को हटा दिया है?
रेगन

बेशक नहीं, लेकिन यह अप्रासंगिक है क्योंकि जब मैं एक छवि का पुनर्निर्माण करता हूं, तो मैं अभी भी मूलmy/base
satoru

जवाबों:


139

एक डॉकफाइल बनाने की कोशिश करें जो कुछ इस तरह दिखे:

FROM my/base

WORKDIR /srv
ADD ./requirements.txt /srv/requirements.txt
RUN pip install -r requirements.txt
ADD . /srv
RUN python setup.py install

ENTRYPOINT ["run_server"]

डॉकर पाइप इंस्टॉल के दौरान कैश का उपयोग करेगा जब तक आप इस पर कोई बदलाव नहीं करते हैं requirements.txt, भले ही इस तथ्य के बावजूद कि अन्य कोड फ़ाइलों .को बदल दिया गया था या नहीं। यहाँ एक उदाहरण है।


यहाँ एक सरल Hello, World!कार्यक्रम है:

$ tree
.
├── Dockerfile
├── requirements.txt
└── run.py   

0 directories, 3 file

# Dockerfile

FROM dockerfile/python
WORKDIR /srv
ADD ./requirements.txt /srv/requirements.txt
RUN pip install -r requirements.txt
ADD . /srv
CMD python /srv/run.py

# requirements.txt
pytest==2.3.4

# run.py
print("Hello, World")

Docker निर्माण का उत्पादन:

Step 1 : WORKDIR /srv
---> Running in 22d725d22e10
---> 55768a00fd94
Removing intermediate container 22d725d22e10
Step 2 : ADD ./requirements.txt /srv/requirements.txt
---> 968a7c3a4483
Removing intermediate container 5f4e01f290fd
Step 3 : RUN pip install -r requirements.txt
---> Running in 08188205e92b
Downloading/unpacking pytest==2.3.4 (from -r requirements.txt (line 1))
  Running setup.py (path:/tmp/pip_build_root/pytest/setup.py) egg_info for package pytest
....
Cleaning up...
---> bf5c154b87c9
Removing intermediate container 08188205e92b
Step 4 : ADD . /srv
---> 3002a3a67e72
Removing intermediate container 83defd1851d0
Step 5 : CMD python /srv/run.py
---> Running in 11e69b887341
---> 5c0e7e3726d6
Removing intermediate container 11e69b887341
Successfully built 5c0e7e3726d6

आइए संशोधित करें run.py:

# run.py
print("Hello, Python")

फिर से बनाने की कोशिश करें, नीचे आउटपुट है:

Sending build context to Docker daemon  5.12 kB
Sending build context to Docker daemon 
Step 0 : FROM dockerfile/python
---> f86d6993fc7b
Step 1 : WORKDIR /srv
---> Using cache
---> 55768a00fd94
Step 2 : ADD ./requirements.txt /srv/requirements.txt
---> Using cache
---> 968a7c3a4483
Step 3 : RUN pip install -r requirements.txt
---> Using cache
---> bf5c154b87c9
Step 4 : ADD . /srv
---> 9cc7508034d6
Removing intermediate container 0d7cf71eb05e
Step 5 : CMD python /srv/run.py
---> Running in f25c21135010
---> 4ffab7bc66c7
Removing intermediate container f25c21135010
Successfully built 4ffab7bc66c7

जैसा कि आप ऊपर देख सकते हैं, इस बार निर्माण के दौरान डॉकटर कैश का उपयोग करते हैं। अब, चलो अद्यतन करें requirements.txt:

# requirements.txt

pytest==2.3.4
ipython

नीचे docker बिल्ड का आउटपुट है:

Sending build context to Docker daemon  5.12 kB
Sending build context to Docker daemon 
Step 0 : FROM dockerfile/python
---> f86d6993fc7b
Step 1 : WORKDIR /srv
---> Using cache
---> 55768a00fd94
Step 2 : ADD ./requirements.txt /srv/requirements.txt
---> b6c19f0643b5
Removing intermediate container a4d9cb37dff0
Step 3 : RUN pip install -r requirements.txt
---> Running in 4b7a85a64c33
Downloading/unpacking pytest==2.3.4 (from -r requirements.txt (line 1))
  Running setup.py (path:/tmp/pip_build_root/pytest/setup.py) egg_info for package pytest

Downloading/unpacking ipython (from -r requirements.txt (line 2))
Downloading/unpacking py>=1.4.12 (from pytest==2.3.4->-r requirements.txt (line 1))
  Running setup.py (path:/tmp/pip_build_root/py/setup.py) egg_info for package py

Installing collected packages: pytest, ipython, py
  Running setup.py install for pytest

Installing py.test script to /usr/local/bin
Installing py.test-2.7 script to /usr/local/bin
  Running setup.py install for py

Successfully installed pytest ipython py
Cleaning up...
---> 23a1af3df8ed
Removing intermediate container 4b7a85a64c33
Step 4 : ADD . /srv
---> d8ae270eca35
Removing intermediate container 7f003ebc3179
Step 5 : CMD python /srv/run.py
---> Running in 510359cf9e12
---> e42fc9121a77
Removing intermediate container 510359cf9e12
Successfully built e42fc9121a77

ध्यान दें कि पाइप इंस्टॉल के दौरान कैकर कैश का उपयोग कैसे नहीं करते हैं यदि यह काम नहीं करता है, तो अपने docker संस्करण की जाँच करें।

Client version: 1.1.2
Client API version: 1.13
Go version (client): go1.2.1
Git commit (client): d84a070
Server version: 1.1.2
Server API version: 1.13
Go version (server): go1.2.1
Git commit (server): d84a070

2
यह काम नहीं करता है, क्योंकि जब भी डॉकटर एक ADDनिर्देश देखता है , तो कैश अमान्य हो जाता है।
सटोरू

1
मुझे यकीन नहीं है कि यह काम क्यों नहीं करता है। लेकिन आवश्यकताओं पर कोई बदलाव नहीं है ADD ./requirements.txt /srv/requirements.txt। कपड़ा (<src> on ), फिर डॉकटर को कैश का उपयोग करना चाहिए। Dockerfile दस्तावेज़ पर seciton जोड़ें देखें ।
नेसोट

16
यदि आवश्यकताएं नहीं बदलती हैं तो हाँ यह कैश का उपयोग करेगा। लेकिन अगर आवश्यकताएँ। कपड़ा बदल जाता है तो सभी आवश्यकताएँ डाउनलोड हो जाती हैं। क्या मैं कैश से लोड करने के लिए डॉक कंटेनर में पाइप कैश वॉल्यूम माउंट कर सकता हूं?
जीतू

7
इस उत्तर की कुंजी यह है कि आप आवश्यकताओं को जोड़ते ADD requirements.txt /srvहैं। Txt ( इससे पहले कि आप पाइप चलाते हैं RUN pip install -r requirements.txt), और पाइप चलाने के बाद अन्य सभी फ़ाइलों को जोड़ दें । इस प्रकार, उन्हें निम्नलिखित क्रम में होना चाहिए: (1) ADD requirements.txt /srv; (2) RUN pip install -r requirements.txt; 3)ADD . /srv
Engelen

2
कृपया ध्यान दें कि
veuncent

29

नेटवर्क गतिविधि को कम करने के लिए, आप pipअपने होस्ट मशीन पर कैश निर्देशिका को इंगित कर सकते हैं ।

अपने मेजबान के पाइप कैश निर्देशिका के साथ अपने डॉक कंटेनर को अपने कंटेनर के पाइप कैश निर्देशिका में माउंट करें। docker runकमांड इस तरह दिखना चाहिए:

docker run -v $HOME/.cache/pip-docker/:/root/.cache/pip image_1

फिर अपने डॉकरफाइल में अपनी आवश्यकताओं को कमांड के बजाय ENTRYPOINTकथन (या CMDकथन) के एक भाग के रूप में स्थापित करें RUN। यह महत्वपूर्ण है, क्योंकि (टिप्पणियों में बताया गया है) छवि निर्माण के दौरान माउंट उपलब्ध नहीं है (जब RUNबयान निष्पादित किए जाते हैं)। डॉकर फ़ाइल को इस तरह दिखना चाहिए:

FROM my/base

ADD . /srv

ENTRYPOINT ["sh", "-c", "pip install -r requirements.txt && python setup.py install && run_server"]

4
ऐसा नहीं है कि ओपी अपने उपयोग के मामले में क्या देख रहा था, लेकिन अगर आपका एक बिल्ड सर्वर है तो यह एक अच्छा विचार है
ओडेन

2
यह समस्याओं के लिए एक नुस्खा की तरह लगता है, विशेष रूप से डिफ़ॉल्ट होस्ट कैश को इंगित करने का सुझाव। आप संभावित रूप से आर्च-विशिष्ट पैकेज मिश्रण कर रहे हैं।
जियाकोमो लाकवा

@GiacomoLacava धन्यवाद, यह बहुत अच्छी बात है। मैंने अपने उत्तर को समायोजित किया और उस हिस्से को हटा दिया जिसने मेजबान की कैश निर्देशिका का फिर से उपयोग करने का सुझाव दिया था।
जैकब कुकुल

24

मैं समझता हूं कि इस प्रश्न के कुछ लोकप्रिय उत्तर पहले से ही हैं। लेकिन पैकेज प्रबंधकों के लिए फ़ाइलों को कैश करने का एक नया तरीका है। मुझे लगता है कि यह भविष्य में एक अच्छा जवाब हो सकता है जब BuildKit अधिक मानक हो जाता है।

डॉक 18.09 के रूप में बिल्डकिट के लिए प्रयोगात्मक समर्थन है । बिल्डकिट कदमों में बढ़ते बाहरी संस्करणों के लिए प्रयोगात्मक समर्थन सहित डॉकफाइल में कुछ नई सुविधाओं के लिए समर्थन जोड़ता है RUN। यह हमें चीजों के लिए कैश बनाने की अनुमति देता है $HOME/.cache/pip/

हम requirements.txtउदाहरण के रूप में निम्न फ़ाइल का उपयोग करेंगे :

Click==7.0
Django==2.2.3
django-appconf==1.0.3
django-compressor==2.3
django-debug-toolbar==2.0
django-filter==2.2.0
django-reversion==3.0.4
django-rq==2.1.0
pytz==2019.1
rcssmin==1.0.6
redis==3.3.4
rjsmin==1.1.0
rq==1.1.0
six==1.12.0
sqlparse==0.3.0

एक विशिष्ट उदाहरण पायथन Dockerfileजैसा दिख सकता है:

FROM python:3.7
WORKDIR /usr/src/app
COPY requirements.txt /usr/src/app/
RUN pip install -r requirements.txt
COPY . /usr/src/app

BuildKit के साथ DOCKER_BUILDKITपर्यावरण वैरिएबल का उपयोग करके सक्षम हम pipलगभग 65 सेकंड में बिना पढ़े हुए चरण का निर्माण कर सकते हैं :

$ export DOCKER_BUILDKIT=1
$ docker build -t test .
[+] Building 65.6s (10/10) FINISHED                                                                                                                                             
 => [internal] load .dockerignore                                                                                                                                          0.0s
 => => transferring context: 2B                                                                                                                                            0.0s
 => [internal] load build definition from Dockerfile                                                                                                                       0.0s
 => => transferring dockerfile: 120B                                                                                                                                       0.0s
 => [internal] load metadata for docker.io/library/python:3.7                                                                                                              0.5s
 => CACHED [1/4] FROM docker.io/library/python:3.7@sha256:6eaf19442c358afc24834a6b17a3728a45c129de7703d8583392a138ecbdb092                                                 0.0s
 => [internal] load build context                                                                                                                                          0.6s
 => => transferring context: 899.99kB                                                                                                                                      0.6s
 => CACHED [internal] helper image for file operations                                                                                                                     0.0s
 => [2/4] COPY requirements.txt /usr/src/app/                                                                                                                              0.5s
 => [3/4] RUN pip install -r requirements.txt                                                                                                                             61.3s
 => [4/4] COPY . /usr/src/app                                                                                                                                              1.3s
 => exporting to image                                                                                                                                                     1.2s
 => => exporting layers                                                                                                                                                    1.2s
 => => writing image sha256:d66a2720e81530029bf1c2cb98fb3aee0cffc2f4ea2aa2a0760a30fb718d7f83                                                                               0.0s
 => => naming to docker.io/library/test                                                                                                                                    0.0s

अब, प्रायोगिक शीर्ष लेख जोड़ें और RUNपायथन पैकेजों को कैश करने के लिए चरण को संशोधित करें :

# syntax=docker/dockerfile:experimental

FROM python:3.7
WORKDIR /usr/src/app
COPY requirements.txt /usr/src/app/
RUN --mount=type=cache,target=/root/.cache/pip pip install -r requirements.txt
COPY . /usr/src/app

आगे बढ़ो और अब एक और निर्माण करो। इसमें उतना ही समय लगना चाहिए। लेकिन इस बार यह हमारे नए कैश माउंट में पायथन पैकेजों को कैशिंग कर रहा है:

$ docker build -t pythontest .
[+] Building 60.3s (14/14) FINISHED                                                                                                                                             
 => [internal] load build definition from Dockerfile                                                                                                                       0.0s
 => => transferring dockerfile: 120B                                                                                                                                       0.0s
 => [internal] load .dockerignore                                                                                                                                          0.0s
 => => transferring context: 2B                                                                                                                                            0.0s
 => resolve image config for docker.io/docker/dockerfile:experimental                                                                                                      0.5s
 => CACHED docker-image://docker.io/docker/dockerfile:experimental@sha256:9022e911101f01b2854c7a4b2c77f524b998891941da55208e71c0335e6e82c3                                 0.0s
 => [internal] load .dockerignore                                                                                                                                          0.0s
 => [internal] load build definition from Dockerfile                                                                                                                       0.0s
 => => transferring dockerfile: 120B                                                                                                                                       0.0s
 => [internal] load metadata for docker.io/library/python:3.7                                                                                                              0.5s
 => CACHED [1/4] FROM docker.io/library/python:3.7@sha256:6eaf19442c358afc24834a6b17a3728a45c129de7703d8583392a138ecbdb092                                                 0.0s
 => [internal] load build context                                                                                                                                          0.7s
 => => transferring context: 899.99kB                                                                                                                                      0.6s
 => CACHED [internal] helper image for file operations                                                                                                                     0.0s
 => [2/4] COPY requirements.txt /usr/src/app/                                                                                                                              0.6s
 => [3/4] RUN --mount=type=cache,target=/root/.cache/pip pip install -r requirements.txt                                                                                  53.3s
 => [4/4] COPY . /usr/src/app                                                                                                                                              2.6s
 => exporting to image                                                                                                                                                     1.2s
 => => exporting layers                                                                                                                                                    1.2s
 => => writing image sha256:0b035548712c1c9e1c80d4a86169c5c1f9e94437e124ea09e90aea82f45c2afc                                                                               0.0s
 => => naming to docker.io/library/test                                                                                                                                    0.0s

लगभग 60 सेकंड। हमारे पहले निर्माण के समान।

requirements.txtकैश अमान्यकरण और फिर से चलाने के लिए (जैसे दो पैकेजों के बीच एक नई लाइन जोड़ने के रूप में) एक छोटा सा बदलाव करें:

$ docker build -t pythontest .
[+] Building 15.9s (14/14) FINISHED                                                                                                                                             
 => [internal] load build definition from Dockerfile                                                                                                                       0.0s
 => => transferring dockerfile: 120B                                                                                                                                       0.0s
 => [internal] load .dockerignore                                                                                                                                          0.0s
 => => transferring context: 2B                                                                                                                                            0.0s
 => resolve image config for docker.io/docker/dockerfile:experimental                                                                                                      1.1s
 => CACHED docker-image://docker.io/docker/dockerfile:experimental@sha256:9022e911101f01b2854c7a4b2c77f524b998891941da55208e71c0335e6e82c3                                 0.0s
 => [internal] load build definition from Dockerfile                                                                                                                       0.0s
 => => transferring dockerfile: 120B                                                                                                                                       0.0s
 => [internal] load .dockerignore                                                                                                                                          0.0s
 => [internal] load metadata for docker.io/library/python:3.7                                                                                                              0.5s
 => CACHED [1/4] FROM docker.io/library/python:3.7@sha256:6eaf19442c358afc24834a6b17a3728a45c129de7703d8583392a138ecbdb092                                                 0.0s
 => CACHED [internal] helper image for file operations                                                                                                                     0.0s
 => [internal] load build context                                                                                                                                          0.7s
 => => transferring context: 899.99kB                                                                                                                                      0.7s
 => [2/4] COPY requirements.txt /usr/src/app/                                                                                                                              0.6s
 => [3/4] RUN --mount=type=cache,target=/root/.cache/pip pip install -r requirements.txt                                                                                   8.8s
 => [4/4] COPY . /usr/src/app                                                                                                                                              2.1s
 => exporting to image                                                                                                                                                     1.1s
 => => exporting layers                                                                                                                                                    1.1s
 => => writing image sha256:fc84cd45482a70e8de48bfd6489e5421532c2dd02aaa3e1e49a290a3dfb9df7c                                                                               0.0s
 => => naming to docker.io/library/test                                                                                                                                    0.0s

केवल 16 सेकंड के बारे में!

हमें यह स्पीडअप मिल रहा है क्योंकि हम अब सभी पायथन पैकेज डाउनलोड नहीं कर रहे हैं। उन्हें पैकेज प्रबंधक ( pipइस मामले में) द्वारा कैश किया गया था और कैश वॉल्यूम माउंट में संग्रहीत किया गया था। वॉल्यूम माउंट रन कदम को प्रदान किया जाता है ताकि pipहमारे पहले से डाउनलोड किए गए पैकेज का पुन: उपयोग कर सकें । यह किसी भी डॉकर परत कैशिंग के बाहर होता है

बड़े पर लाभ अधिक बेहतर होना चाहिए requirements.txt

टिप्पणियाँ:

  • यह प्रायोगिक Dockerfile सिंटैक्स है और इसे ऐसे ही माना जाना चाहिए। आप इस समय उत्पादन में इसके साथ निर्माण नहीं करना चाह सकते हैं।
  • BuildKit सामान Docker Compose या अन्य टूल्स के तहत काम नहीं करता है जो सीधे Docker API का उपयोग करते हैं। डॉकटर कंपोज़ में अब इसके लिए 1.25.0 का समर्थन है। देखें कि आप बिल्डकिट को डॉकटर-कंपोज के साथ कैसे सक्षम करते हैं?
  • फिलहाल कैश को प्रबंधित करने के लिए कोई प्रत्यक्ष इंटरफ़ेस नहीं है। यह शुद्ध है जब आप एक करते हैं docker system prune -a

उम्मीद है, इन सुविधाओं के निर्माण के लिए यह डॉकर में बना देगा और BuildKit डिफ़ॉल्ट हो जाएगा। यदि / जब ऐसा होता है तो मैं इस उत्तर को अपडेट करने का प्रयास करूंगा।


मैं पुष्टि कर सकता हूं कि यह समाधान बहुत अच्छी तरह से काम करता है। मेरा निर्माण एक मिनट से केवल 2.2 सेकंड में नीचे चला गया। धन्यवाद @ andy-shinn
क्वूइट


नोट: यदि आप डॉक को चलाने के लिए SUDO का उपयोग कर रहे हैं, तो आपको संभवतः करने की आवश्यकता है: sudo DOCKER_BUILDKIT = 1 ...
Vinícius M

मुझे यह त्रुटि मिल रही है: - फ्रंटेंड dockerfile.v0 के साथ हल करने में विफल: LLB परिभाषा बनाने में विफल: Dockerfile पार्स त्रुटि पंक्ति 10: अज्ञात ध्वज: आरोह
मयूर डांगर

वह आवाज़ जैसे आपने टिप्पणी को याद किया Dockerfileया डॉकर संस्करण सबसे ऊपर है वह बहुत पुरानी है। मैं आपकी सभी डिबगिंग जानकारी के साथ एक नया प्रश्न बनाऊंगा।
एंडी शिन

-10

मैंने पाया कि एक बेहतर तरीका सिर्फ वॉल्यूम के रूप में पायथन साइट-पैकेज डायरेक्टरी को जोड़ना है।

services:
    web:
        build: .
        command: python manage.py runserver 0.0.0.0:8000
        volumes:
            - .:/code
            -  /usr/local/lib/python2.7/site-packages/

इस तरह मैं सिर्फ एक पूर्ण पुनर्निर्माण करने के बिना नए पुस्तकालयों को स्थापित कर सकता हूं।

संपादित करें : इस उत्तर की अवहेलना करें , ऊपर जुकुल के उत्तर ने मेरे लिए काम किया। मेरा इरादा साइट-संकुल फ़ोल्डर को कैश करना था । यह कुछ और जैसा दिखता है:

volumes:
   - .:/code
   - ./cached-packages:/usr/local/lib/python2.7/site-packages/

डाउनलोड फ़ोल्डर कैशिंग हालांकि क्लीनर है। यह भी पहियों को कैश करता है, इसलिए यह ठीक से कार्य को प्राप्त करता है।


2
और जब आप एक अलग मशीन पर इस डॉकफाइल को बनाने की कोशिश करते हैं तो क्या होता है। यह एक स्थायी समाधान नहीं है।
हारून मैकमिलिन

वास्तव में उलझन में, यह निकला छोटी गाड़ी है और मैं वास्तव में क्यों नहीं पता था। क्या आप कुछ और जानकारी दे सकते हैं।
jaywhy13

3
आपकी docker की छवि होस्ट सिस्टम की स्थिति पर निर्भर करती है। यह डॉकटर की अधिकांश उपयोगिता से बचता है। इसमें जो कुछ भी छवि की जरूरत है उसे स्थापित किया जाना चाहिए। सभी आश्रितों को स्थापित करने के लिए Dockerfile का उपयोग करें। यदि आप हर बार पैकेज को फिर से डाउनलोड करने से बचना चाहते हैं तो जुकुल से उत्तर देने के लिए पाइप कैश माउंट करने का तरीका है।
हारून मैकमिलिन

2
लाइटबुल सिर्फ धन्यवाद के साथ चला गया। मैं वास्तव में वीएम से साइट-पैकेज निर्देशिका को माउंट करने की कोशिश कर रहा था, न कि मेजबान। काफी निरीक्षण किया। मुझे लगता है कि मैं आत्मा में वही करने की कोशिश कर रहा था जैसा कि जकुलकुल ने सुझाया था। स्पष्टता के लिए धन्यवाद!
jaywhy13

@AaronMcMillin वह वास्तव में मेजबान पर एक पथ पर निर्भर नहीं है। वह कंटेनर में साइट-संकुल को एक गुमनाम वॉल्यूम में बढ़ा रहा है। हालांकि अभी भी एक बुरा विचार है
ruohola
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.