What is {{ }} in dockerfile?

I want to make a minor change in openedx image, because of the low network condition in china, I need to change the apt source mirror.
But when I run docker build -t in tutor’s build/openedx directory, it says
Error response from daemon: Dockerfile parse error line 86: unknown instruction: {{
And I don’t know what {{ patch… }} mean and how it works, how to build my own docker image with the dockerfile in tutor. Please help me with some instructions. Thanks very much!

Hi @teruun! Funny how things seem obvious to me when in fact this kind of information is documented nowhere :slight_smile:

Please first take a look at the following post which explains how tutor works: Logic of config.yml and JSON config files

So, to answer your question: the files in tutor/templates are Jinja2 template files that are rendered in the $(tutor config printroot)/env folder. This is why these files contain {{ some_variable_name }} stuff.

As for {{ patch "..." }} instructions: these are places that can be customised by plugins. See the relevant docs: https://docs.tutor.overhang.io/plugins.html#patches

Does that answer your question?

I created an issue to remind me to improve the docs on this specific topic: https://github.com/overhangio/tutor/issues/273

In your case, it will be difficult to improve the base openedx docker image without forking the project. It would be easier for you if you could easily modify the base docker image (“ubuntu:16.04”), for instance with a configuration variable. You would then be able to point to your own China-optimized ubuntu image. Please let me know how you manage to solve this problem.

Hi, thank you regis, i substituted the “ubuntu:16.04” with my own china-optimized ubuntu and now it can download things rather quickly. I installed a shadowsocks client in it, changed the apt source with aliyun’s source mirror, and everytime when tutor needs to download things with git, I invoked the shadowsocks.
And I also added a new language folder under “/openedx/locale” path in the openedx image.

A problem is the shadowsocks client can’t run in detached mode, so I have to edit your dockerfile and everytime git clone occurs, I have to run shadowsocks first. Docker ubuntu seems don’t support systemd.

Hi, regis, thanks again. after I used my own docker image, the development mode lms and cms is working find but the forum no longer works, and the production mode also having an error: tutor_local_openedx-assets_1 exited with code 0

Below is the error message displayed in discussion forum. Any idea how to fix this?

Environment:

Request Method: GET
Request URL: http://localhost:8000/courses/course-v1:edX+DemoX+Demo_Course/discussion/forum/

Django Version: 1.11.21
Python Version: 2.7.12
Installed Applications:
[‘django.contrib.auth’,
‘django.contrib.contenttypes’,
‘django.contrib.humanize’,
‘django.contrib.messages’,
‘django.contrib.redirects’,
‘django.contrib.sessions’,
‘django.contrib.sites’,
‘django.contrib.staticfiles’,
‘djcelery’,
‘openedx.core.djangoapps.common_initialization.apps.CommonInitializationConfig’,
‘lms_initialization.apps.LMSInitializationConfig’,
‘openedx.core.djangoapps.common_views’,
‘simple_history’,
‘config_models’,
‘openedx.core.djangoapps.config_model_utils’,
‘waffle’,
‘openedx.core.djangoapps.service_status’,
‘status’,
‘edxmako.apps.EdxMakoConfig’,
‘pipeline’,
‘static_replace’,
‘webpack_loader’,
‘web_fragments’,
‘openedx.core.djangoapps.plugin_api’,
‘openedx.core.djangoapps.contentserver’,
‘openedx.core.djangoapps.site_configuration’,
‘openedx.core.djangoapps.video_config’,
‘openedx.core.djangoapps.video_pipeline’,
‘courseware’,
‘student.apps.StudentConfig’,
‘static_template_view’,
‘staticbook’,
‘track’,
‘eventtracking.django.apps.EventTrackingConfig’,
‘util’,
‘lms.djangoapps.certificates.apps.CertificatesConfig’,
‘dashboard’,
‘lms.djangoapps.instructor_task’,
‘openedx.core.djangoapps.course_groups’,
‘bulk_email’,
‘branding’,
‘support’,
‘openedx.core.djangoapps.external_auth’,
‘django_openid_auth’,
‘provider’,
‘provider.oauth2’,
‘edx_oauth2_provider’,
‘oauth2_provider’,
‘openedx.core.djangoapps.oauth_dispatch.apps.OAuthDispatchAppConfig’,
‘third_party_auth’,
‘oauth_provider’,
‘openedx.core.djangoapps.auth_exchange’,
‘wiki’,
‘django_notify’,
‘course_wiki’,
‘mptt’,
‘sekizai’,
‘wiki.plugins.links’,
‘course_wiki.plugins.markdownedx’,
‘django.contrib.admin’,
‘debug’,
‘openedx.core.djangoapps.util.apps.UtilConfig’,
‘django_comment_client’,
‘django_comment_common’,
‘discussion_api’,
‘notes’,
‘edxnotes’,
‘splash’,
‘rest_framework’,
‘openedx.core.djangoapps.user_api’,
‘shoppingcart’,
‘notification_prefs’,
‘notifier_api’,
‘course_modes.apps.CourseModesConfig’,
‘enrollment’,
‘entitlements.apps.EntitlementsConfig’,
‘bulk_enroll’,
‘lms.djangoapps.verify_student.apps.VerifyStudentConfig’,
‘openedx.core.djangoapps.dark_lang’,
‘microsite_configuration.apps.MicrositeConfigurationConfig’,
‘rss_proxy’,
‘openedx.core.djangoapps.embargo’,
‘course_action_state’,
‘edx_jsme’,
‘django_countries’,
‘mobile_api’,
‘social_django’,
‘survey.apps.SurveyConfig’,
‘lms.djangoapps.lms_xblock.apps.LMSXBlockConfig’,
‘submissions’,
‘openassessment’,
‘openassessment.assessment’,
‘openassessment.fileupload’,
‘openassessment.workflow’,
‘openassessment.xblock’,
‘edxval’,
‘openedx.core.djangoapps.content.course_overviews.apps.CourseOverviewsConfig’,
‘openedx.core.djangoapps.content.block_structure.apps.BlockStructureConfig’,
‘lms.djangoapps.course_blocks’,
‘openedx.core.djangoapps.coursegraph.apps.CoursegraphConfig’,
‘mailing’,
‘corsheaders’,
‘openedx.core.djangoapps.cors_csrf’,
‘lms.djangoapps.commerce.apps.CommerceConfig’,
‘openedx.core.djangoapps.credit.apps.CreditConfig’,
‘lms.djangoapps.teams’,
‘xblock_django’,
‘openedx.core.djangoapps.programs.apps.ProgramsConfig’,
‘openedx.core.djangoapps.catalog’,
‘openedx.core.djangoapps.self_paced’,
‘sorl.thumbnail’,
‘milestones’,
‘gating.apps.GatingConfig’,
‘statici18n’,
‘openedx.core.djangoapps.api_admin’,
‘openedx.core.djangoapps.verified_track_content’,
‘learner_dashboard’,
‘badges.apps.BadgesConfig’,
‘django_sites_extensions’,
‘email_marketing.apps.EmailMarketingConfig’,
‘release_util’,
‘celery_utils’,
‘openedx.core.djangoapps.crawlers’,
‘database_fixups’,
‘openedx.core.djangoapps.waffle_utils’,
‘lms.djangoapps.course_goals’,
‘openedx.features.course_bookmarks’,
‘openedx.features.course_experience’,
‘openedx.features.course_search’,
‘openedx.features.enterprise_support.apps.EnterpriseSupportConfig’,
‘openedx.features.learner_profile’,
‘openedx.features.learner_analytics’,
‘openedx.features.portfolio_project’,
‘openedx.features.course_duration_limits’,
‘openedx.features.content_type_gating’,
‘experiments’,
‘django_filters’,
‘rest_framework_swagger’,
‘csrf.apps.CsrfAppConfig’,
‘edx_sga’,
‘organizations’,
‘enterprise’,
‘consent’,
‘integrated_channels.integrated_channel’,
‘integrated_channels.degreed’,
‘integrated_channels.sap_success_factors’,
‘integrated_channels.xapi’,
‘django_object_actions’,
u’openedx.core.djangoapps.password_policy.apps.PasswordPolicyConfig’,
u’openedx.core.djangoapps.ace_common.apps.AceCommonConfig’,
u’lms.djangoapps.discussion.apps.DiscussionConfig’,
u’openedx.core.djangoapps.schedules.apps.SchedulesConfig’,
u’lms.djangoapps.grades.apps.GradesConfig’,
u’openedx.core.djangoapps.user_authn.apps.UserAuthnConfig’,
u’openedx.core.djangoapps.plugins.apps.PluginsConfig’,
u’openedx.core.djangoapps.zendesk_proxy.apps.ZendeskProxyConfig’,
u’openedx.core.djangoapps.credentials.apps.CredentialsConfig’,
u’openedx.core.djangoapps.bookmarks.apps.BookmarksConfig’,
u’lms.djangoapps.instructor.apps.InstructorConfig’,
u’openedx.features.journals.apps.JournalsConfig’,
u’openedx.core.djangoapps.theming.apps.ThemingConfig’,
u’edx_proctoring.apps.EdxProctoringConfig’,
u’completion.apps.CompletionAppConfig’,
‘debug_toolbar’,
‘debug_toolbar_mongo’]
Installed Middleware:
[‘openedx.core.lib.x_forwarded_for.middleware.XForwardedForMiddleware’,
‘crum.CurrentRequestUserMiddleware’,
‘edx_django_utils.cache.middleware.RequestCacheMiddleware’,
‘edx_django_utils.monitoring.middleware.MonitoringCustomMetricsMiddleware’,
‘mobile_api.middleware.AppVersionUpgrade’,
‘openedx.core.djangoapps.header_control.middleware.HeaderControlMiddleware’,
‘microsite_configuration.middleware.MicrositeMiddleware’,
‘django_comment_client.middleware.AjaxExceptionMiddleware’,
‘django.middleware.common.CommonMiddleware’,
‘django.contrib.sites.middleware.CurrentSiteMiddleware’,
‘edx_rest_framework_extensions.auth.jwt.middleware.JwtAuthCookieMiddleware’,
‘django_sites_extensions.middleware.RedirectMiddleware’,
‘openedx.core.djangoapps.safe_sessions.middleware.SafeSessionMiddleware’,
‘openedx.core.djangoapps.cache_toolbox.middleware.CacheBackedAuthenticationMiddleware’,
‘student.middleware.UserStandingMiddleware’,
‘openedx.core.djangoapps.contentserver.middleware.StaticContentServer’,
‘openedx.core.djangoapps.user_api.middleware.UserTagsEventContextMiddleware’,
‘django.contrib.messages.middleware.MessageMiddleware’,
‘track.middleware.TrackMiddleware’,
‘corsheaders.middleware.CorsMiddleware’,
‘openedx.core.djangoapps.cors_csrf.middleware.CorsCSRFMiddleware’,
‘openedx.core.djangoapps.cors_csrf.middleware.CsrfCrossDomainCookieMiddleware’,
‘django.middleware.csrf.CsrfViewMiddleware’,
‘splash.middleware.SplashMiddleware’,
‘openedx.core.djangoapps.geoinfo.middleware.CountryMiddleware’,
‘openedx.core.djangoapps.embargo.middleware.EmbargoMiddleware’,
‘openedx.core.djangoapps.lang_pref.middleware.LanguagePreferenceMiddleware’,
‘openedx.core.djangoapps.dark_lang.middleware.DarkLangMiddleware’,
‘django.middleware.locale.LocaleMiddleware’,
‘django_comment_client.utils.ViewNameMiddleware’,
‘codejail.django_integration.ConfigureCodeJailMiddleware’,
‘ratelimitbackend.middleware.RateLimitMiddleware’,
‘openedx.core.djangoapps.session_inactivity_timeout.middleware.SessionInactivityTimeout’,
‘django.middleware.clickjacking.XFrameOptionsMiddleware’,
‘courseware.middleware.CacheCourseIdMiddleware’,
‘courseware.middleware.RedirectMiddleware’,
‘course_wiki.middleware.WikiAccessMiddleware’,
‘openedx.core.djangoapps.theming.middleware.CurrentSiteThemeMiddleware’,
‘waffle.middleware.WaffleMiddleware’,
‘openedx.features.enterprise_support.middleware.EnterpriseMiddleware’,
‘edx_django_utils.cache.middleware.TieredCacheMiddleware’,
‘edx_rest_framework_extensions.middleware.RequestMetricsMiddleware’,
‘edx_rest_framework_extensions.auth.jwt.middleware.EnsureJWTAuthSettingsMiddleware’,
‘openedx.core.djangoapps.site_configuration.middleware.SessionCookieDomainOverrideMiddleware’,
‘django_comment_client.utils.QueryCountDebugMiddleware’,
‘debug_toolbar.middleware.DebugToolbarMiddleware’]

Traceback:

File “/openedx/venv/local/lib/python2.7/site-packages/django/core/handlers/exception.py” in inner
41. response = get_response(request)

File “/openedx/venv/local/lib/python2.7/site-packages/django/core/handlers/base.py” in _legacy_get_response
249. response = self._get_response(request)

File “/openedx/venv/local/lib/python2.7/site-packages/django/core/handlers/base.py” in _get_response
187. response = self.process_exception_by_middleware(e, request)

File “/openedx/venv/local/lib/python2.7/site-packages/django/core/handlers/base.py” in _get_response
185. response = wrapped_callback(request, *callback_args, **callback_kwargs)

File “/openedx/venv/local/lib/python2.7/site-packages/django/utils/decorators.py” in inner
185. return func(*args, **kwargs)

File “/openedx/venv/local/lib/python2.7/site-packages/django/contrib/auth/decorators.py” in _wrapped_view
23. return view_func(request, *args, **kwargs)

File “/openedx/edx-platform/lms/djangoapps/discussion/views.py” in wrapped_view
188. return view_func(request, course_key, *args, **kwargs)

File “/openedx/edx-platform/lms/djangoapps/discussion/views.py” in forum_form_discussion
282. return tab_view.get(request, course_id, ‘discussion’)

File “/openedx/venv/local/lib/python2.7/site-packages/django/utils/decorators.py” in _wrapper
67. return bound_func(*args, **kwargs)

File “/openedx/venv/local/lib/python2.7/site-packages/django/utils/decorators.py” in _wrapped_view
149. response = view_func(request, *args, **kwargs)

File “/openedx/venv/local/lib/python2.7/site-packages/django/utils/decorators.py” in bound_func
63. return func.get(self, type(self))(*args2, **kwargs2)

File “/openedx/venv/local/lib/python2.7/site-packages/django/utils/decorators.py” in _wrapper
67. return bound_func(*args, **kwargs)

File “/openedx/edx-platform/common/djangoapps/util/views.py” in inner
49. response = view_func(request, *args, **kwargs)

File “/openedx/venv/local/lib/python2.7/site-packages/django/utils/decorators.py” in bound_func
63. return func.get(self, type(self))(*args2, **kwargs2)

File “/openedx/venv/local/lib/python2.7/site-packages/django/utils/decorators.py” in _wrapper
67. return bound_func(*args, **kwargs)

File “/openedx/edx-platform/openedx/features/enterprise_support/api.py” in inner
313. return view_func(request, course_id, *args, **kwargs)

File “/openedx/venv/local/lib/python2.7/site-packages/django/utils/decorators.py” in bound_func
63. return func.get(self, type(self))(*args2, **kwargs2)

File “/openedx/edx-platform/lms/djangoapps/courseware/views/views.py” in get
523. return CourseTabView.handle_exceptions(request, course, exception)

File “/openedx/edx-platform/lms/djangoapps/courseware/views/views.py” in get
521. return super(CourseTabView, self).get(request, course=course, page_context=page_context, **kwargs)

File “/openedx/venv/local/lib/python2.7/site-packages/web_fragments/views.py” in get
26. fragment = self.render_to_fragment(request, **kwargs)

File “/openedx/edx-platform/lms/djangoapps/courseware/views/views.py” in render_to_fragment
656. return tab.render_to_fragment(request, course, **kwargs)

File “/openedx/edx-platform/common/lib/xmodule/xmodule/tabs.py” in render_to_fragment
294. return self.fragment_view.render_to_fragment(request, course_id=unicode(course.id), **kwargs)

File “/openedx/edx-platform/lms/djangoapps/discussion/views.py” in render_to_fragment
704. base_context = _create_base_discussion_view_context(request, course_key)

File “/openedx/edx-platform/lms/djangoapps/discussion/views.py” in _create_base_discussion_view_context
405. user_info = cc_user.to_dict()

File “/openedx/edx-platform/lms/lib/comment_client/models.py” in to_dict
59. self.retrieve()

File “/openedx/edx-platform/lms/lib/comment_client/models.py” in retrieve
64. self._retrieve(*args, **kwargs)

File “/openedx/edx-platform/lms/lib/comment_client/user.py” in _retrieve
152. metric_tags=self._metric_tags,

File “/openedx/edx-platform/lms/lib/comment_client/utils.py” in perform_request
70. timeout=config.connection_timeout

File “/openedx/venv/local/lib/python2.7/site-packages/requests/api.py” in request
60. return session.request(method=method, url=url, **kwargs)

File “/openedx/venv/local/lib/python2.7/site-packages/requests/sessions.py” in request
533. resp = self.send(prep, **send_kwargs)

File “/openedx/venv/local/lib/python2.7/site-packages/requests/sessions.py” in send
646. r = adapter.send(request, **kwargs)

File “/openedx/venv/local/lib/python2.7/site-packages/requests/adapters.py” in send
516. raise ConnectionError(e, request=request)

Exception Type: ConnectionError at /courses/course-v1:edX+DemoX+Demo_Course/discussion/forum/
Exception Value: SOCKSHTTPConnectionPool(host=‘forum’, port=4567): Max retries exceeded with url: /api/v1/users/3?complete=True&request_id=8c4c4059-9134-490f-9483-de32d89bb047 (Caused by NewConnectionError(‘<urllib3.contrib.socks.SOCKSConnection object at 0x7f79af3706d0>: Failed to establish a new connection: [Errno 111] Connection refused’,))

I found that I was in an older version of tutor, I’ll try upgrading tutor. Sorry for disturbing.